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