将任何数据类型序列化为vector <uint8_t> - 使用reinterpret_cast?

ezp*_*zpz 7 c++ serialization templates network-programming

我没有找到与搜索直接相关的任何内容,所以请原谅这是否重复.

我想要做的是通过网络连接序列化数据.我的方法是将我需要传输的所有内容转换std::vector< uint8_t >为接收方并将数据解压缩到适当的变量中.我的方法如下:

template <typename T>
inline void pack (std::vector< uint8_t >& dst, T& data) {
    uint8_t * src = static_cast < uint8_t* >(static_cast < void * >(&data));
    dst.insert (dst.end (), src, src + sizeof (T));
}   

template <typename T>
inline void unpack (vector <uint8_t >& src, int index, T& data) {
    copy (&src[index], &src[index + sizeof (T)], &data);
}
Run Code Online (Sandbox Code Playgroud)

我正在使用它

vector< uint8_t > buffer;
uint32_t foo = 103, bar = 443;
pack (buff, foo);
pack (buff, bar);

// And on the receive side
uint32_t a = 0, b = 0;
size_t offset = 0;
unpack (buffer, offset, a);
offset += sizeof (a);
unpack (buffer, offset, b);
Run Code Online (Sandbox Code Playgroud)

我担心的是

uint8_t * src = static_cast < uint8_t* >(static_cast < void * >(&data));

line(我理解也是如此reinterpret_cast).没有双重演员,有没有更好的方法来实现这一目标?

我天真的方法就是使用static_cast< uint8_t* >(&data)哪个失败了.我过去被告知reinterpret_cast很糟糕.所以我想尽可能避免它(或我目前的构造).

当然,总有uint8_t * src = (uint8_t *)(&data).

建议?

jdm*_*hal 17

我的建议是忽略所有告诉你reinterpret_cast不好的人.他们告诉你它很糟糕,因为采用一种类型的内存映射并假装它是另一种类型通常不是一个好习惯.但在这种情况下,这正是您想要做的,因为您的整个目的是将内存映射作为一系列字节进行传输.

它比使用双精度要好得多static_cast,因为它完全详细说明了你正在采用一种类型并故意假装它是其他东西的事实.这种情况正是如此reinterpret_cast,并且使用空指针中介避免使用它只是模糊了你的意思而没有任何好处.

另外,我确信你已经意识到了这一点,但请注意T中的指针.


man*_*lio 8

你的情况正是如此reinterpret_cast,它比双重更简单,static_cast并清楚地记录你在做什么.

为了安全起见,您应该使用unsigned char而不是uint8_t:

  • reinterpret_castunsigned char *,然后解引用所得指针是安全的和便携式和通过是明确允许[basic.lval]§3.10/ 10
  • do reinterpret_castto std::uint8_t *然后解除引用结果指针是违反严格别名规则的行为,如果std::uint8_t实现为扩展无符号整数类型,则是未定义的行为.

    如果存在,则uint8_t必须始终具有相同的宽度unsigned char.但是,它不一定是同一类型; 它可能是一个独特的扩展整数类型.它也不需要具有相同的表示unsigned char(请参阅何时uint8_t≠unsigned char?).

    (这不是完全假设的:使[u]int8_t特殊的扩展整数类型允许一些积极的优化)

如果你真的想要uint8_t,你可以添加一个:

static_assert(std::is_same<std::uint8_t, unsigned char>::value,
              "We require std::uint8_t to be implemented as unsigned char");
Run Code Online (Sandbox Code Playgroud)

这样代码就不会在导致未定义行为的平台上编译.

  • +1 因为这比链接的 `static_cast` 更好,尤其是关于 `uint8_t` 的警告。我读过这样的一篇文章,甚至可能是同一篇文章,在过去 - 很快就不得不做很多`s/uint8_t/unsigned char/g` ;) (2认同)