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

我读过这篇关于C / C ++严格别名的文章 。 我认为这同样适用于C ++。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

实际上,这个代码已经具有UB,你可以取消引用reinterpret_cast ed整数指针,甚至不需要调用严格别名规则。 不仅如此,如果你不是很小心,直接重新解释你的数据包结构可能会导致各种问题,具体取决于struct packing和endianness。

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