首页 文章

在C 11中使用严格别名,是否将_write_定义为char *,然后将_read_定义为别名的nonchar *?

提问于
浏览
3

有许多关于严格别名的讨论(特别是“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]的变化? (显然有 endpoints 和表示的考虑因素,这不是我的关注点 . )

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

如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:...各种其他条件... char或unsigned char类型 .

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

在反序列化时,这是特别有意义的;将数据直接从线路引入对象是方便有效的,而不需要从char缓冲区到对象的中间memcpy() .

2 回答

  • 2

    是否将_write_定义为char *,然后将_read_定义为别名的nonchar *?

    是 .

    印刷值是否必须反映[alias-write]的变化?

    是 .

    严格别名说(( unsignedchar* 可以别名 . "access"一词表示读写操作 .

  • 0

    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的其他标准不仅没有解决这个根本性的错误,而是继续使用相同的破碎方法 .

相关问题