用更好的替代方案替换reinterpret_cast

Replacing reinterpret_cast with better alternatives?

本文关键字:替换 reinterpret cast 方案 更好      更新时间:2023-10-16

我在我的项目中有几个地方,我使用reinterpret_cast从流中读取/写入无符号整数。考虑以下函数:

size_t ReadSize(std::stringstream& stream) {
  char buf[sizeof(size_t)];
  stream.read(buf, sizeof(size_t));
  return *(reinterpret_cast<size_t*>(buf));
}
void WriteSize(std::stringstream& stream, size_t n) {
  stream.write(reinterpret_cast<char*>(&n), sizeof(size_t));
}

我开始对使用reinterpret_cast感到有点不舒服,尽管我对它没有任何问题,所以我想知道,是否有更好的替代方案?假设流中只有4个字节应该表示这个整数。

我认为

static_cast在这里也不适用。任何建议吗?

注:我目前不关心可移植性或使用reinterpet_cast可能产生的其他平台特定问题。

read(和write)函数被指定为接受char*时,您实际上不必传递一个字符数组,只需在read(或write)调用中转换指向实际变量的指针:

std::size_t size;
if (stream.read(reinterpret_cast<char*>(&size), sizeof(size_t)))
    return size;
return 0;  // Or something else on error

在一个无关的注意事项上,我建议您将stream参数更改为std::istream引用,然后您可以对任何输入流使用该函数。

所以你的代码的问题是,如果一个小端系统写数据,而一个大端系统读它。

这里,reinterpret_cast<>将取位图像并应用它,而不考虑任何数据不兼容。

优先顺序为:-

  • const_cast仅用于删除/添加const。
  • dynamic_cast将预先创建的对象转换为兼容的基/派生对象。
  • static_cast使用编译时信息执行与dynamic_cast相同形式的转换
  • reinterpret_cast将内存视为源和目标的联合。
  • C cast (void*)f;使用reinterpret_cast/static_cast中的一个转换类型。

避免使用C cast。这是因为您无法真正知道编译器将选择什么。const_cast/dynamic_cast不能解决你的问题。

所以最好的选择是reinterpret_cast

由于使用了stringstream,因此可以直接访问它用作缓冲区的字符串:

ReadSize(std::stringstream& stream) {
  return *(reinterpret_cast<size_t*>(stream.str().c_str()));
}

这样可以节省一些复制。

不管怎样,这不是你的问题。只有当您的流提供的数据与您的机器正在处理的数据端相同时,您的代码才会按预期工作。您可能更喜欢显式地处理端序:
ReadSize(std::istream& stream) {
  char buf[sizeof(size_t)];
  stream.read(buf, sizeof(size_t));
  return (static_case<size_t>(buf[0]) << 24) | 
         (static_case<size_t>(buf[1]) << 16) |
         (static_case<size_t>(buf[2]) << 9) |
         (static_case<size_t>(buf[3]));
}
顺便说一下,你也去掉了reinterpret_cast<>

您的代码对size_t的大小进行了假设,即使在Windows上也不总是4字节。如果将4个字节写入流,并且您尝试使用sizeof(size_t)为8的编译代码读取它会发生什么?

您可以使用下面的函数安全且可移植地(不妨)将字节转换为整数。当然,它假定所提供的数组足够大。

template<class T>
T ComposeBytes(const char *bytes)
{
    T x = 0;
    for (size_t i = 0; i < sizeof(T); i++)
    {
        x |= (static_cast<unsigned char>(bytes[i]) << (i * CHAR_BIT));
    }
    return x;
}

编辑:修复了char被签名的问题。