通过强制转换为int来访问原始内存会违反严格的别名吗?

时间:2016-06-19 04:13:41

标签: c++ memory strict-aliasing

假设我想为int动态分配空间,并将最大可表示值写入该内存。想到这个代码:

auto rawMem = std::malloc(sizeof(int));         // rawMem's type is void*
*(reinterpret_cast<int*>(rawMem)) = INT_MAX;    // INT_MAX from <limits.h>

此代码是否违反了C ++关于strict aliasing的规则? g ++和clang ++都不会抱怨-Wall -pedantic

如果代码没有违反严格的别名,为什么不呢? std::malloc返回void*,因此虽然我不知道std::malloc返回的内存的静态和动态类型是什么,但没有理由认为int。我们不会以charunsigned char

的形式访问内存

我想认为代码是犹太洁食,但如果是,我想知道原因。

只要我在附近,我也想知道内存分配函数(std::mallocstd::operator new)返回的内存的静态和动态类型。

1 个答案:

答案 0 :(得分:4)

严格别名规则允许编译器假定无法通过两个或多个不同类型的指针访问内存中的相同位置。

请考虑以下代码:

int* pi = ...;
double* pd = ...;

const int i1 = *pi;    // (1)
*pd = 123.456;         // (2)
const int i2 = *pi;    // (3)

使用严格别名规则分析此代码表明i2 == i1,因为pi指向的位置不应在(1)和(3)之间修改。因此,编译器可以消除变量i1i2中的一个(假设程序不接受其中任何一个的地址)。通常,严格别名规则在优化代码时为编译器提供了更多自由。

在您的示例中,您通过malloc()获取内存位置。编译器不假定该内存位置的任何类型(即该内存位置的静态和动态类型都是...... ummm ...无类型的原始内存,但由于char[]类型的特殊状态在严格别名规则中,我们也可以合法地将该内存位置视为char s的数组。严格别名规则尚未应用于新的内存位置,原因很简单,因为没有可以在分析中使用的类型指针。您可以通过使用所需类型的对象初始化该类型来为该位置指定类型。对于基本类型或POD类型,reinterpret_cast后跟赋值(就像在您的示例中一样)是初始化该内存位置的有效方法,但对于具有非平凡构造函数的类型,您需要构建一个展示位置为new的对象。从那时起,内存位置将停止作为原始内存,并受到严格别名规则的约束。