通过指向int的指针对char数组进行别名是合法的吗?

时间:2016-08-09 23:39:16

标签: c++ language-lawyer strict-aliasing

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

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的存在会让我相信这个可能。

3 个答案:

答案 0 :(得分:5)

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

正在访问的对象的类型为char,但用于访问的glvalue类型为int

char的“对象的动态类型”仍为char。 (dynamic type仅与派生类的静态类型不同)。 C ++也没有任何等效的C“有效类型”,它允许通过将赋值运算符用于malloc'd空间来“创建”类型化对象。

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

您可以对char数组执行相同的操作,例如:

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

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

答案 1 :(得分:-1)

union构造在这里可能很有用。

unionstruct类似,只是union的所有元素都占据相同的存储区域。

换句话说,就像FORTRAN的EQUIVALENCE声明一样,它们是“查看同一事物的不同方式”。因此,例如:

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

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

union通常与typedef一起使用,如此StackOverflow文章所示:C: typedef union

答案 2 :(得分:-3)

*ptr = 0;

写入一个int,因此它是对int的访问,其值为int的左值,因此部分代码没问题。

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