我对C/ c++严格混叠理解正确吗?

Do I understand C/C++ strict-aliasing correctly?

本文关键字:c++ 我对      更新时间:2023-10-16

我读过一篇关于C/c++严格混叠的文章。我认为这同样适用于c++。

据我所知,严格混叠用于重新排列代码以实现性能优化。这就是为什么两个不同类型(在c++中是不相关的)的指针不能指向相同的内存位置。

这是否意味着只有当内存被修改时才会出现问题?除了内存对齐可能存在的问题。

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

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

这里的问题与其说是严格的混叠,不如说是结构表示要求。

首先,可以安全地将charsigned charunsigned char任何一个其他类型(在您的示例中为unsigned int)别名。这允许您编写自己的内存复制循环,只要它们是使用char类型定义的。这在C99(§6.5)中得到以下语言的授权:

, 6。访问其存储值的对象的有效类型是该对象的声明类型(如果有的话)。[脚注:分配的对象没有声明的类型][…]如果一个值被复制到一个没有声明类型的对象中,使用Memcpy或memmove,或者作为字符类型的数组复制,则为有效类型的已修改对象的Value是复制值的对象的有效类型(如果有的话)。为对没有声明类型的对象的所有其他访问,该对象的有效类型为只是用于访问的左值的类型。

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

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

类似的语言可以在c++ 0x草案N3242§3.11/10中找到,尽管它不清楚何时分配对象的"动态类型"(我很感激任何关于char数组动态类型的进一步参考,POD对象已被复制为具有正确对齐的char数组)。

因此,混叠在这里不是问题。然而,严格阅读该标准表明,c++实现在选择unsigned int的表示时有很大的自由。

作为一个随机的例子, unsigned ints可能是一个24位的整数,用4个字节表示,8个填充位点缀;如果这些填充位中的任何一个与某个(常量)模式不匹配,则将其视为陷阱表示,并且对指针进行解引用将导致崩溃。这可能实现吗?也许不是。但是,从历史上看,有奇偶校验位和其他奇数的系统,因此直接从网络读取到unsigned int通过严格的标准读取,是不合适的。

现在,填充位的问题在今天的大多数系统中主要是一个理论问题,但值得注意。如果你打算坚持PC硬件,你真的不需要担心它(但不要忘记你的ntohl s -端序仍然是一个问题!)

当然,

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

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

实际上,在您解引用reinterpret_cast ed整数指针时,这段代码已经具有UB,甚至不需要调用严格混叠规则。不仅如此,如果你不够小心,直接重新解释到你的包结构可能会导致各种各样的问题,这取决于结构包装和端序。

考虑到所有这些,并且您已经调用了UB,我怀疑它"可能工作"在多个编译器上,并且您可以自由地承担这个(可能可测量的)风险。