7

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

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

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

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

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

2 回答 2

7

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

首先,在 , 或 与任何其他类型之间使用别名是安全的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 ints 可能是一个 24 位整数,以 4 个字节表示,其中散布着 8 个填充位;如果这些填充位中的任何一个与某个(常量)模式不匹配,则将其视为陷阱表示,并且取消引用指针将导致崩溃。这是一个可能的实现吗?也许不是。但是,历史上一直存在具有奇偶校验位和其他奇数的系统,因此通过严格阅读标准,直接从网络unsigned int读取. 是不洁净的。

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

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

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

于 2011-09-06T14:48:29.723 回答
0

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

鉴于所有这些,并且您已经在调用 UB,我怀疑它“可能在多个编译器上工作”,您可以自由承担(可能是可衡量的)风险。

于 2011-09-06T14:49:04.663 回答