在 C++11 中使用严格别名时,它是否定义为_write_ 到 char*,然后从别名 nonchar* _read_?

With strict aliasing in C++11, is it defined to _write_ to a char*, then _read_ from an aliased nonchar*?

有很多关于严格别名的讨论(特别是“What is the strict aliasing rule?" and "Strict aliasing rule and 'char *' pointers”),但这是一个极端情况,我没有看到明确解决。

考虑这段代码:

int x;
char *x_alias = reinterpret_cast<char *>(&x);
x = 1;
*x_alias = 2;  // [alias-write]
printf("x is now %d\n", x);

打印的值必须反映 [alias-write] 中的变化吗? (显然有字节序和表示方面的考虑,这不是我关心的问题。)

C++11 规范中著名的 [basic.lval] 子句使用了这种语言(强调我的):

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:

  • ... various other conditions ...
  • a char or unsigned char type.

我不知道 "access" 是只指读操作(从非字符对象读取字符)还是写操作(将字符写入非字符对象)。如果规范中有 "access" 的正式定义,我找不到它,但在其他地方,规范似乎使用 "access" 进行读取,使用 "update" 进行写入。

这在反序列化时特别有用;将数据直接从连线传输到对象中既方便又高效,不需要从字符缓冲区到对象的中间 memcpy()。

is it defined to _write_ to a char*, then _read_ from an aliased nonchar*?

是的。

Must the printed value reflect the change in [alias-write]?

是的。

严格别名表示 ((un)signed) char* 可以为任何东西起别名。 "access"这个词表示读操作和写操作。

C89 标准的作者希望允许例如

int thing;
unsigned char *p = &x;
int i;
for (i=0; i<sizeof thing; i++)
  p[i] = getbyte();

int thing = somevalue();
unsigned char *p = &x;
int i;
for (i=0; i<sizeof thing; i++)
  putbyte(p[i]);

但不要求编译器处理给定的任何可能的别名 喜欢:

/* global definitions */
int thing;
double *p;

int x(double *p)
{
  thing = 1;
  *p = 1.0;
  return thing;
}

支持和不支持的情况有两种不同之处:(1) 在要支持的情况下,使用字符类型指针而不是其他类型进行访问,以及 (2)在相关事物的地址转换为另一种类型之后,使用该指针对存储的所有访问都在使用原始左值进行下一次访问之前进行。不幸的是,该标准的作者只认为第一个是重要的,尽管第二个是识别别名可能很重要的情况的更可靠的方法。如果标准专注于第二个,它可能不需要编译器识别您的示例中的别名。但实际上,该标准要求编译器在程序使用字符类型时识别别名,尽管这会对处理实际字符数据的代码的性能产生不必要的影响。

C 和 C++ 的其他标准没有修复这个根本性错误,而是简单地继续使用相同的错误方法。