确实通过铸造访问原始记忆会违反严格的混叠

Does accessing raw memory through a cast to an int violate strict aliasing?

本文关键字:记忆 原始 访问      更新时间:2023-10-16

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

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

该代码是否违反了C 关于严格混叠的规则?G 和Clang 都不向-Wall -pedantic投诉。

如果代码不违反严格的混叠,为什么不呢?std::malloc返回void*,因此,尽管我不知道std::malloc返回的内存的静态和动态类型,但没有理由认为这是int。而且我们不会以charunsigned char的方式访问内存。

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

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

严格的混叠规则允许编译器假设可通过不同类型的两个或多个指针访问内存中的相同位置。

考虑以下代码:

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()获得存储位置。编译器不假定该内存位置的任何类型(即该内存位置的静态和动态类型是...嗯...未型的原始内存,但是由于char[]类型的特殊状态在严格的别名中规则我们还可以合法地将该内存位置视为char s的数组。严格的别名规则尚未适用于新的内存位置,原因很简单,因为没有可以参与分析的打字指针。是您通过使用所需类型的对象将其指定为该位置的类型。如果是原始类型或POD类型,则reinterpret_cast然后进行分配(就像您的示例中一样)是初始化该内存位置的有效方法,但是对于具有非平凡构造函数的类型,您需要与位置new。从那时起,内存位置就停止了原始内存,并受到严格的混叠规则的约束。