我的项目中有一些地方,我使用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机器写这个。
答案 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
将内存视为源和目标的联合。(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
已签名的问题。