原始类型指针之间铸造(Casting between primitive type pointers

2019-07-19 15:31发布

被明确定义如下:

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

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

所述intPtr不正确(在这两种情况的至少一种)对准。 难道非法只是拥有它呢? 难道UB用它在任何阶段? 你如何使用它,以及如何能不好吗?

Answer 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)比原来更高。或者,在这里试图转换错位指针总是导致一个空指针。)



Answer 2:

一般地,结果是不确定的(5.2.10p7)如果的对准要求int比的更大的char ,他们通常会。 其结果将是所述类型的有效的值int * ,因此它可以是例如印刷为具有指针operator<<或转换为intptr_t

因为结果都有一个未指定的值,除非通过执行指定它是未定义的行为来间接它并执行左值到右值转换对所得int左值(除了在未计算的上下文)。 转换回char *不一定会往返。

然而,如果原始char *本身就是由铸造的结果int * ,然后投给int *计为一个往返下半年; 在这种情况下,铸造被定义。

特别是,在上述其中的情况下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对象。



文章来源: Casting between primitive type pointers