用更好的替代方案替换reinterpret_cast
Replacing reinterpret_cast with better alternatives?
我在我的项目中有几个地方,我使用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
被签名的问题。
相关文章:
- 模板参数替换失败,并且未完成隐式转换
- 如何用转义符替换字符串中的所有特殊字符
- 为什么除非添加括号,否则构造函数上的模板替换会失败?
- 在一个读写器队列中,我可以用volatile替换原子吗
- 用符号版本替换对函数的所有调用
- 如何通过替换顺序代码的while循环来添加OpenMP for循环
- 替换基于地图的所有引用
- 按平均值替换数组中的元素
- 我可以在这里替换什么,因为我不能在 C# 中使用隐式变量的 lambda 函数?
- 如何将字节数组元素替换为修改的十六进制 ASCII 符号?
- 初始化 std::vector 替换为单大括号而不是双大括号
- 删除/替换C++字符串中的多字符 (ÿû)
- 将 malloc 替换为数组
- 如何替换此示例代码片段中已弃用的handler_type_t或 boost::asio::handler_type?
- 如何在C++中用'\'替换''来处理转义序列?
- 替换密码:哪一个?
- 替换 C++17 中移除的绑定 1st
- 将 Boost MPL 容器替换为 C++17 功能
- C++:如何用单个命令替换复杂的迭代?
- C++ 替换字节数组中项的顺序