c++ - 关于将指向 char 的指针转换为另一种类型指针的问题
问题描述
#include <iostream>
struct Test{
int a;
int b;
};
int main(){
char* buffer = (char*)malloc(sizeof(char)*32); //#a
char* ptr = buffer + 4; //#b
new(ptr) Test; //#c
char* ptr2 = buffer + 4; //#d
Test* tptr = reinterpret_cast<Test*>(ptr2); //#e
tptr->a = 1; // #f
}
考虑上面的代码,在点 处#a
,分配函数malloc
分配一个存储区域并隐式创建一个类型为 的数组对象char[32]
,这在以下规则中有所提及:
一些操作被描述为在指定的存储区域内隐式创建对象。对于指定为隐式创建对象的每个操作,该操作会在其指定的存储区域中隐式创建并启动零个或多个隐式生命周期类型([basic.types])的对象的生命周期,如果这样做会导致程序有明确的行为。如果没有这样的对象集会给程序定义的行为,则程序的行为是未定义的。如果多个这样的对象集会给程序定义的行为,则未指定创建哪个这样的对象集。
所以, at 的代码#b
定义得很好,因为指针buffer
可以被认为是指向数组的第一个元素,它满足规则expr.add#4。at的代码#c
也很好定义,它将在ptr
指向的存储处构造一个Test类型的对象。#d
与 相同#b
,也很好定义。
但是,请考虑#e
. 现在,指针指向(由 )创建ptr2
的第四个元素,该元素是 char 类型的对象,其生命周期由于其存储而结束,被 类型的对象重用。表达式等价于。array
malloc
Test
reinterpret_cast<Test*>(ptr2)
static_cast<Test*>(static_cast<void*>(ptr2))
“指向 cv1 void 的指针”类型的纯右值可以转换为“指向 cv2 T 的指针”类型的纯右值,其中 T 是对象类型,而 cv2 与 cv1 具有相同的 cv 限定或大于 cv1 的 cv 限定。如果原始指针值表示内存中一个字节的地址A,并且A不满足T的对齐要求,那么得到的指针值是未指定的。否则,如果原始指针值指向对象 a,并且存在与 a 指针可互转换的类型为 T(忽略 cv 限定)的对象 b,则结果是指向 b 的指针。否则,指针值不会因转换而改变。
根据上述规则,类型的对象Test
不能与 char 类型的对象进行指针互转换。所以,我认为结果仍然是指向 char 类型对象的指针,它是数组的第四个元素,只是它的生命周期已经结束。
所以,我想知道#f
由于tptr
不指向类型的对象,代码是否具有未定义的行为Test
?或者相反,指针是否tptr
确实指向类型的对象Test
并且代码定义明确?如果我错过了其他一些规则,请指出。
解决方案
#f
由于tptr
不指向类型的对象,代码是否具有未定义的行为Test
?
该程序具有未定义的行为,因为#a
, 因为malloc
被定义为触发隐式对象创建并返回指向合适的已创建对象的指针,但是将为程序的其余部分提供定义行为的对象集是空的。
推荐阅读
- visual-c++ - Helloworld MFC 应用程序抛出异常
- autocad - 通过 appload (autoLISP) 加载例程时运行函数
- javascript - UnhandledPromiseRejectionWarning :异步回调函数中的错误处理
- javascript - Location.watchPositionAsync 未将状态设置为位置
- python - Pandas:修改类型列表的另一列中指示的列
- php - 未捕获的错误:调用成员函数 prepare() (PDO, php)
- angular - 单击 angular mat-chip 选择不触发 valueChanges 和芯片值在 valueChanes 事件中不可用
- javascript - 动态创建具有 onAction={} 属性的 JSX 元素,不更新状态(它们已损坏)
- java - 使用 JTA 时无法使用 EntityTransaction。使用非 jta
- java - 根据用户的要求制作一个从 x 打印到 y 数字的程序