5

以下是明确定义的:

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

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

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

4

2 回答 2

3

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对象的地址。

于 2013-02-08T13:20:53.467 回答
1

首先,当然:指针保证在第一种情况下对齐(根据 §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)

于 2013-02-08T14:25:27.300 回答