c++ - 按位将 uint32_t 强制转换为 C/C++ 中的 float

标签 c++ casting floating-point type-punning

我正在从网络接收缓冲区,该缓冲区已转换为 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/

相关文章:

floating-point - 我应该如何处理 float ,这些数字可以变得如此之小以至于变成零

math - float 学有问题吗?

c++ - 在C++中获取堆数组的大小

sql - 将 JSON 字符串转换为十进制的问题

c++ - 用输入表示数组中元素的数量吗?

c++ - 如何返回好的类型的对象

c++ - 将 Eigen::ArrayXXd 转换为 Eigen::MatrixXd

python - 将字符串解析为具有不同分隔符的 float

c++ - 如何在 C++ 中使用 libbz2 压缩目录

c++ - QTableView 中标题单元格中的复选框