通过指向 int 的指针为 char 数组起别名合法吗?

Is it legal to alias a char array through a pointer to int?

我知道标准中明确允许以下内容:

int n = 0;
char *ptr = (char *) &n;
cout << *ptr;

这个呢?

alignas(int) char storage[sizeof(int)];
int *ptr = (int *) &storage[0];
*ptr = 0;
cout << *ptr;

本质上,我是在问别名规则是否允许通过指向另一种类型的指针访问一系列字符。如果可能,我希望参考标准中指示某种方式的部分。

标准的某些部分让我感到矛盾; (3.10.10) 似乎表明它是未定义的行为,假设 storage 的动态类型不是 int。但是,我不清楚动态类型的定义,std::aligned_storage 的存在会让我相信这个 可能的。

union 结构在这里可能会有用。

union 类似于 struct,不同之处在于 union 的所有元素都占用 相同的 存储区域。

换句话说,它们 "different ways to view the same thing," 就像 FORTRAN 的 EQUIVALENCE 声明。因此,例如:

union {
  int   foo;
  float bar;
  char  bletch[8];
}

提供了三种完全不同的方式来考虑相同的存储区域。 (union 的存储大小是其最长部分的大小。)foobarbletch 都是 的同义词 存储。

union 通常与 typedef 一起使用,如这篇 Whosebug 文章中所示:C: typedef union.

代码 int *ptr = (int *) &storage[0]; *ptr = 0; 通过违反严格的别名规则 (C++14 [basic.lval]/10) 导致未定义的行为

正在访问的对象具有类型 char 但用于访问的左值具有类型 int.

char 的 "dynamic type of the object" 仍然是 char。 (dynamic type 仅在派生 class 的情况下不同于静态类型)。 C++ 也没有 C 的 "effective type" 的等价物,它允许通过使用赋值运算符进入 malloc'd space.

来使类型化对象成为 "created"

关于 std::aligned_storage 的正确使用,您应该使用 placement-new 在存储中创建一个对象。使用 placement-new 被认为是结束 char(或其他)对象的生命周期,并创建指定类型的新对象(动态存储持续时间),重新使用相同的存储。那么就不会有严格的混叠违规。

您可以对 char 数组做同样的事情,例如:

alignas(int) char storage[sizeof(int)];
int *ptr = new(storage) int;
*ptr = 0;
cout << *ptr;

请注意,内置类型 int 不需要伪析构函数调用或 delete。如果使用具有非平凡初始化的 class 类型,则需要这样做。 Link to further reading

*ptr = 0;

写入一个int,所以它是对int的访问,左值是int类型,所以这部分代码没问题。

转换在道德上是好的,但是 C/C++ 标准文本没有清楚地描述转换、指针或任何基本的东西。