在 C++11 中使用严格的混叠时,它是否定义为 _write_ 到 char*,然后从别名的非 char* 读取_

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

本文关键字:char 读取 write 定义 别名 然后 C++11 是否      更新时间:2023-10-16

有很多关于严格混叠的讨论(特别是"什么是严格混叠规则?"和"严格的混叠规则和'char *'指针"(,但这是一个我没有看到明确解决的极端情况。

请考虑以下代码:

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

打印的值必须反映 [别名写入] 中的更改吗?(显然有字节序和表示方面的考虑,这不是我关心的问题。

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

如果程序尝试通过以下类型之一以外的 glvalue 访问对象的存储值,则行为是未定义的:

  • 。各种其他条件...
  • charunsigned char类型。

我无法弄清楚"访问"是指读取操作(从非字符对象读取字符(还是也指写入操作(将字符写入非字符对象(。如果在规范中有"访问"的正式定义,我找不到它,但在其他地方,规范似乎使用"访问"进行读取,使用"更新"进行写入。

这在反序列化时特别有趣;将数据直接从线路引入对象既方便又高效,而不需要中间 memcpy(( 从 char-buffer 到对象中。

它是否定义为_写入_到字符*,然后从别名非字符*_读取_?

是的。

打印的值必须反映 [别名写入] 中的更改吗?

是的。

严格混叠说((un(signed(char*可以混叠任何东西。"访问"一词意味着读取和写入操作。

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( 在相关事物的地址转换为另一种类型后,使用该指针对存储的所有访问都是在下一次使用原始 lvalue 进行访问之前进行的。 不幸的是,该标准的作者只认为第一个是重要的,尽管第二个是识别别名可能很重要的情况的更可靠的方法。 如果标准侧重于第二个,则可能不需要编译器识别示例中的别名。 但是,该标准要求编译器在程序使用字符类型时随时识别别名,尽管这会对处理实际字符数据的代码的性能产生不必要的影响。

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