用更好的替代品替换 reinterpret_cast?

Replacing reinterpret_cast with better alternatives?

我在我的项目中有几个地方使用 reinterpret_cast 到 read/write 来自流的无符号整数。考虑以下函数:

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 在这里也不适用。有什么建议吗?

P.S。我目前不关心使用 reinterpet_cast 可能引起的可移植性或其他特定于平台的问题。我正在为 Windows 机器写这篇文章。

虽然 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

在一个不相关的说明中,我建议您将流参数更改为 std::istream 引用,然后您可以将该函数用于任何输入流。

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

在这里,reinterpret_cast<> 将获取位图并应用它,而不管任何数据不兼容。

优先顺序是:-

  • const_cast仅用于remove/add const.
  • dynamic_cast 将预先创建的对象转换为兼容 base/derived.
  • 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 被签名的问题。