我正在从网络接收缓冲区,该缓冲区已转换为 32 位字数组。我有一个词被我的接口(interface)文档定义为 IEEE-754 float 。我需要从缓冲区中提取这个词。在不调用转换的情况下很难从一种类型转换为另一种类型。这些位已经符合 IEEE-754 浮点标准,我不想重新安排任何位。
我的第一个尝试是将 uint32_t
的地址转换为 void*
,然后将 void*
转换为 float*
,然后解引用为 float
:
float ieee_float(uint32_t f)
{
return *((float*)((void*)(&f)));
}
error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
我的第二次尝试是这样的:
float ieee_float(uint32_t f)
{
union int_float{
uint32_t i;
float f;
} tofloat;
tofloat.i = f;
return tofloat.f;
}
然而,街上的消息是 union 是完全不安全的。从不是最近写入的 union 成员中读取是未定义的行为。
所以我尝试了一种更 C++ 的方法:
float ieee_float(uint32_t f)
{
return *reinterpret_cast<float*>(&f);
}
error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
我的下一个想法是“去他的。我为什么还要处理指针?”刚刚试过:
float ieee_float(uint32_t f)
{
return reinterpret_cast<float>(f);
}
error: invalid cast from type ‘uint32_t {aka unsigned int}’ to type ‘float’
有没有办法在不触发警告/错误的情况下进行转换?我正在使用 -Wall -Werror
使用 g++ 进行编译。我不想触及编译器设置。
我标记 C 是因为 c 解是可以接受的。
最佳答案
在 C++20 中,您可以使用 std::bit_cast
:
float ieee_float(uint32_t f)
{
return std::bit_cast<float>(f);
}
在 C++17 及之前的版本中,正确的方法™ 是:
float ieee_float(uint32_t f)
{
static_assert(sizeof(float) == sizeof f, "`float` has a weird size.");
float ret;
std::memcpy(&ret, &f, sizeof(float));
return ret;
}
GCC 和 Clang 在 -O1
及以上代码为此代码和天真的 reinterpret_cast<float &>(f)
生成相同的程序集(但后者是未定义的行为,在某些情况下可能不起作用)。
关于c++ - 按位将 uint32_t 强制转换为 C/C++ 中的 float ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48803363/