我是否正确理解C / C ++严格别名?

时间:2011-09-06 14:27:07

标签: c++ c strict-aliasing

我看过this article about C/C++ strict aliasing。我认为同样适用于C ++。

据我所知,严格别名用于重新排列代码以进行性能优化。这就是为什么两个不同(在C ++情况下不相关)类型的指针不能引用相同的内存位置的原因。

这是否意味着只有在修改内存时才会出现问题?除了可能存在的问题with memory alignment

例如,处理网络协议或反序列化。我有一个字节数组,动态分配和数据包结构正确对齐。我可以reinterpret_cast到我的数据包结构吗?

char const* buf = ...; // dynamically allocated
unsigned int i = *reinterpret_cast<unsigned int*>(buf + shift); // [shift] satisfies alignment requirements

2 个答案:

答案 0 :(得分:7)

这里的问题不是严格的别名,而是结构表示要求。

首先,在charsigned charunsigned char任何一种其他类型(在您的情况下,{{1})之间别名是安全的这允许您编写自己的内存复制循环,只要它们使用unsigned int类型定义。这在C99(§6.5)中由以下语言授权:

  

6.访问其存储值的对象的有效类型是对象的声明类型(如果有)。 [脚注:已分配的对象没有声明的类型] [...]如果将值复制到没有声明类型的对象中使用   memcpy或memmove,或者被复制为字符类型数组,然后是有效类型   用于该访问的修改对象以及不修改该访问的后续访问   value是从中复制值的对象的有效类型(如果有)。对于   对没有声明类型的对象的所有其他访问,对象的有效类型是   只是用于访问的左值的类型。

     

7.对象的存储值只能由具有以下类型之一的左值表达式访问:[脚注:此列表的目的是指定对象可能或可能没有别名的情况。 ]

     
      
  • 与对象的有效类型兼容的类型
  •   
  • [...]
  •   
  • 字符类型。
  •   

类似的语言可以在C ++ 0x草案N3242§3.11/ 10中找到,虽然在分配对象的“动态类型”时不是很清楚(我很欣赏任何有关动态的进一步参考type是一个char数组,POD对象已被复制为具有正确对齐的char数组。

因此,别名在这里不是问题。但是,严格阅读标准表明C ++实现在选择char的表示时有很大的自由度。

作为一个随机的例子,unsigned int s可能是一个24位整数,以四个字节表示,其中散布着8个填充位;如果这些填充位中的任何一个与某个(常量)模式不匹配,则将其视为陷阱表示,并且取消引用指针将导致崩溃。这可能是实施吗?也许不是。但是,历史上一直存在具有奇偶校验位和其他奇怪性的系统,因此通过严格读取标准直接从网络读取到unsigned int,这不是犹太教。 / p>

现在,填充位的问题在当今的大多数系统中大多是理论问题,但值得注意。如果你打算坚持使用PC硬件,你真的不必担心它(但不要忘记你的unsigned int s - 字节序仍然是个问题!)

当然,结构会让情况变得更糟 - 对齐表示取决于您的平台。我曾经在一个嵌入式平台上工作,其中所有类型都具有1的对齐 - 没有填充永远插入到结构中。在多个平台上使用相同的结构定义时,这可能导致不一致。您可以手动计算数据结构成员的字节偏移量并直接引用它们,也可以使用特定于编译器的对齐指令来控制填充。

因此,在从网络缓冲区直接转换为本机类型或结构时必须小心。但在这种情况下,混叠本身不是问题。

答案 1 :(得分:0)

实际上,在您取消引用reinterpret_cast ed整数指针时,此代码已经具有UB,甚至无需调用严格别名规则。不仅如此,如果您不是很小心,直接重新解释您的数据包结构可能会导致各种问题,具体取决于结构打包和字节顺序。

鉴于这一切,并且你已经在调用UB,我怀疑它在多个编译器上“可能正常工作”,并且你可以自由地承担(可能是可测量的)风险。