以下是明确定义的:
char* charPtr = new char[42];
int* intPtr = (int*)charPtr;
charPtr++;
intPtr = (int*) charPtr;
未intPtr
正确对齐(至少在两种情况下的一种)。放在那里是违法的吗?UB 在任何阶段都在使用它吗?你怎么能用它,你怎么不能?
以下是明确定义的:
char* charPtr = new char[42];
int* intPtr = (int*)charPtr;
charPtr++;
intPtr = (int*) charPtr;
未intPtr
正确对齐(至少在两种情况下的一种)。放在那里是违法的吗?UB 在任何阶段都在使用它吗?你怎么能用它,你怎么不能?
int
通常,如果 的对齐要求大于的对齐要求,则结果未指定(5.2.10p7)char
,通常情况下。结果将是该类型的有效值,int *
因此它可以打印为带有operator<<
或转换为的指针intptr_t
。
因为结果有一个未指定的值,除非由实现指定,否则间接它并对结果int
左值执行左值到右值转换是未定义的行为(在未评估的上下文中除外)。转换回char *
不一定是往返。
但是,如果原始数据char *
本身是 from 转换的结果int *
,则转换 toint *
算作往返的后半部分;在这种情况下,演员表被定义。
特别是,在上面char *
是表达式的结果的情况下new[]
,我们保证(5.3.4p10)char *
指针适当地对齐int
,只要sizeof(int) <= 42
。因为new[]
表达式从分配函数中获取存储空间,所以适用 3.7.4.1p2;void *
指针可以转换为具有基本对齐要求的任何完整对象类型的指针,然后用于访问对象[...],这强烈暗示,连同对 5.3.4p10 的注释,char *
指针同样适用由new[]
表达式返回。在这种情况下,int *
是指向未初始化的指针int
对象,因此对其间接执行左值到右值的转换是未定义的(3.8p6),但分配给它的间接是完全定义的。该int
对象位于分配的存储空间中(3.7.4.1p2),因此将其转换int *
回char *
将产生每 1.8p6 的原始值。这不适用于递增的char *
指针,除非sizeof(int) == 1
它不是int
对象的地址。
首先,当然:指针保证在第一种情况下对齐(根据 §5.3.4/10 和 §3.7.4.1/2),并且在两种情况下都可以正确对齐。(显然,如果sizeof(int) == 1
,但即使不是这种情况,实现也不一定有对齐要求。)
并且说清楚:你的演员都是reinterpret_cast
.
除此之外,这是一个有趣的问题,因为据我所知,就标准而言,两种演员阵容没有区别。转换结果未指定(根据 §5.2.10/7);您甚至不能保证将其转换回 achar*
会产生原始值。(例如,它显然不会在int*
小于 a 的机器上char*
。)
当然,在实践中:标准要求 的返回值与new char[N]
可能适合它的任何值充分对齐,因此您可以保证能够做到:
intPtr = new (charPtr) int;
int
鉴于默认构造函数是无操作的,这与您的演员阵容完全相同。(并假设
sizeof(int) <= 42
。)所以很难想象第一部分失败的实现。您应该可以
intPtr
像使用任何其他合法获得intPtr
的 . 将其转换回 achar*
会以某种方式导致与原始值不同的想法char*
似乎很荒谬。
在第二部分中,所有的赌注都没有了:你绝对不能取消引用指针(除非你的实现另有保证),而且将它转换回char*
结果也很可能会产生不同的结果。(例如,想象一个字寻址的机器,将 a 转换为char*
向上
舍入。然后转换回来将int*
导致 a高于原始值。或者尝试转换未对齐的指针总是导致空指针。)char*
sizeof(int)