在基元类型指针之间进行强制转换

Casting between primitive type pointers

提问人:Luchian Grigore 提问时间:2/8/2013 最后编辑:Luchian Grigore 更新时间:2/8/2013 访问量:1083

问:

以下定义是否明确:

char* charPtr = new char[42];
int* intPtr = (int*)charPtr;

charPtr++;
intPtr = (int*) charPtr;

未正确对齐(在两种情况下的至少一种情况下)。只是把它放在那里是非法的吗?是UB在任何阶段使用它吗?你怎么能使用它,你怎么能不能?intPtr

C++ 语言 - 律师 严格别名

评论

0赞 Mats Petersson 2/8/2013
如果您在此之后尝试使用,则会发生未对齐的访问(在相关处理器上)。所以这绝对是不可接受的。虽然它可能在某些处理器上工作 - 例如,x86 会很乐意,如果速度慢一点,读取未对齐的内存。intPtr
0赞 Bartek Banachewicz 2/8/2013
我认为你可以回放,但投:)后不能使用它不过,我必须检查一下。
0赞 John Dibling 2/8/2013
你说的“你能把它扔回去吗”是什么意思?
0赞 Luchian Grigore 2/8/2013
@JohnDibling移除了该部件(发现需要回铸才能工作)。
2赞 Ivaylo Strandjev 2/8/2013
更好地使用而不是样式铸造。C++static_castC

答:

3赞 ecatmur 2/8/2013 #1

通常,如果 的对齐要求大于 的对齐要求,则结果未指定 (5.2.10p7)。结果将是该类型的有效值,因此可以将其打印为指针或转换为 .intcharint *operator<<intptr_t

由于结果具有未指定的值,因此除非实现指定,否则间接结果并对生成的左值执行左值到右值的转换是未定义的行为(在未计算的上下文中除外)。转换回不一定是往返的。intchar *

但是,如果原件本身是 的铸造结果,则铸造 算作往返的后半部分;在这种情况下,将定义强制转换。char *int *int *

特别是,在上面 是表达式结果的情况下,我们可以保证 (5.3.4p10) 指针是适当对齐的,只要 .由于表达式从分配函数获取其存储,因此适用 3.7.4.1p2;指针可以转换 指向具有基本对齐要求的任何完整对象类型的指针,然后用于访问对象 [...]这与对 5.3.4p10 的注释一起强烈暗示,表达式返回的指针也是如此。在本例中,the 是指向未初始化对象的指针,因此对其间接执行左值到右值的转换是未定义的 (3.8p6),但对其间接的赋值是完全定义的。该对象位于分配的存储 (3.7.4.1p2) 中,因此将转换回将产生每 1.8p6 的原始值。这不适用于递增的指针,除非它不是对象的地址。char *new[]char *intsizeof(int) <= 42new[]void *char *new[]int *intintint *char *char *sizeof(int) == 1int

评论

0赞 Lightness Races in Orbit 2/8/2013
原来是 的结果。char*new char[42]
1赞 James Kanze 2/8/2013 #2

首先,当然:指针保证在 第一种情况(§5.3.4/10 和 §3.7.4.1/2),并且可能是正确的 在这两种情况下都是一致的。(显然,如果 ,但是 即使情况并非如此,实现也不会 必须有对齐要求。sizeof(int) == 1

说清楚一点:你的演员都是.reinterpret_cast

除此之外,这是一个有趣的问题,因为就 我看得出来,就目前而言,两个演员阵容没有区别 标准是有问题的。转换的结果是 未指定(根据 §5.2.10/7);你甚至不能保证 将其转换回 a 将导致 原始值。(例如,在机器上显然不会 其中小于 .)char*int*char*

当然,在实践中:标准要求返回 的值与任何值充分对齐 这可能适合它,因此您可以保证能够:new char[N]

intPtr = new (charPtr) int;

这与你的演员阵容具有完全相同的效果,因为 的默认构造函数是空操作。(并假设 .因此,很难想象实现 其中第一部分失败。您应该能够像使用任何其他合法获得的一样。而 将其转换回 a 的想法会以某种方式产生 在与原始值不同的值中似乎 荒谬。intsizeof(int) <= 42intPtrintPtrchar*char*

在第二部分中,所有的赌注都关闭了:你绝对不能 取消引用指针(除非您的实现保证 否则),也很有可能将其转换回来 产生不同的东西。(想象一个词 寻址机器,例如,将 A 转换为四舍五入。然后转换回来将导致 a 高于原来的。或 尝试转换未对齐的指针总是导致 在 null 指针中。char*char*int*char*sizeof(int)