【问题标题】:How to parse byte array without violating strict aliasing rule?如何在不违反严格的别名规则的情况下解析字节数组?
【发布时间】:2021-07-21 13:14:25
【问题描述】:

我的问题是关于解析字节数组的典型过程,如下代码:

struct Header { /* ... */ };
struct Entry1 { /* ... */ };
struct Entry2 { /* ... */ };

void Parse(char* p) {
  const auto header = reinterpret_cast<Header*>(p);
  p += sizeof(Header);
  const auto ent1 = reinterpret_cast<Entry1*>(p);
  p += sizeof(Entry1);
  const auto ent2 = reinterpret_cast<Entry2*>(p);
}

首先,规范说char* 可以为任何其他指针类型起别名,所以reinterpret_cast&lt;Header*&gt; 是安全的。 但是其他reinterpret_cast statemetns 呢, 他们是否违反了strict aliasing rule,因为p,其类型为char*,已经被别名为Header*?还是安全的,因为p 增加了sizeof(Header)

谢谢。

【问题讨论】:

  • 您可以使用std::memcpy 将字节复制到您的结构中,假设该结构可以简单地复制。如果结构不是可轻松复制的,则需要将字节逐字段解析到结构中。
  • 您使用的是什么版本的 C++? C++20 中的规则发生了变化。
  • 规范说char* 可以为任何其他指针类型起别名,所以reinterpret_cast&lt;Header*&gt; 是安全的。 你有那个倒退。规范说reinterpret_cast&lt;char*&gt;(pointer_to_some_type); 是安全的。反过来可能安全也可能不安全。
  • 看起来你正在重新发明风团。你做的事情叫做序列化。看看boot serialization 库,它可以帮助你解决这个问题。

标签: c++ language-lawyer


【解决方案1】:

首先,规范说char* 可以为任何其他指针类型起别名,所以reinterpret_cast&lt;Header*&gt; 是安全的

虽然重新解释转换本身从来没有 UB,但我不会将其描述为“安全”,因为通过重新解释指针访问的行为可能是未定义的。虽然将任何内容重新解释为 char 数组是可以的,但以另一种方式进行并将 char 数组重新解释为其他内容是不行的。

假设您的课程可以轻松复制,您可以使用std::memcpy

Header h0;
std::size_t offset = sizeof h0;
std::memcpy(&h0, p, offset);
p += offset;

Entry1 e1;
offset = sizeof e1;
std::memcpy(&e1, p, offset);
p += offset;

Entry2 e2;
offset = sizeof e2;
std::memcpy(&e2, p, offset);

但是,请记住,不同的系统可能有不同的对齐要求,因此它们的类中可能有不同的填充量,以及不同大小的整数以及整数中不同的字节顺序(以及不同大小的字节,但我假设这不是 IPC 的典型问题)。因此,这种简单的方法只能在同一个系统中工作,并且对于不同进程之间的通信(如通过 Internet 或文件系统)没有用处。要正确实现这一点,您必须根据协议显式放置每个字节。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-25
    • 1970-01-01
    • 1970-01-01
    • 2015-11-06
    • 1970-01-01
    • 2020-04-11
    • 1970-01-01
    相关资源
    最近更新 更多