用更好的替代品替换reinterpret_cast?

时间:2015-10-25 17:45:48

标签: c++ reinterpret-cast

我的项目中有一些地方,我使用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也不适用于此。有什么提示吗?

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

4 个答案:

答案 0 :(得分:5)

虽然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引用,然后您可以将该函数用于任何输入流。

答案 1 :(得分:1)

所以代码的问题在于,如果一个小端系统写入数据,并且一个大端系统会读取它。

此处,reinterpret_cast<>将获取位图并应用它,无论数据不兼容。

优先顺序为: -

  • const_cast用于删除/仅添加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

答案 2 :(得分:1)

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

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

这可以节省一些复制费用。

无论如何,这不是你的问题。只有在您的流提供的数据与您的计算机正在使用的相同的endianes时,您的代码才能按预期工作。您可能更愿意明确处理endianes:

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

答案 3 :(得分:1)

您的代码假设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已签名的问题。