按位转换uint32_t以在C / C ++中浮动

时间:2018-02-15 09:02:03

标签: c++

我从网络接收缓冲区,该缓冲区被转换为32位字的数组。我有一个单词被我的界面文档定义为ieee float。我需要从缓冲区中提取这个单词。在不调用转换的情况下从一种类型转换为另一种类型很困难。这些位已经符合ieee浮动标准,我不想重新排列任何位。

我的第一次尝试是将uint32_t的地址转换为void*,然后将void*转换为float*,然后取消引用为float }:

float ieee_float(uint32_t f)
{
    return *((float*)((void*)(&f)));
}
  

错误:解除引用类型惩罚指针将破坏严格别名规则[-Werror = strict-aliasing]

我的第二次尝试是这样的:

float ieee_float(uint32_t f)
{
    union int_float{
        uint32_t i;
        float f;
    } tofloat;

    tofloat.i = f;
    return tofloat.f;
}

然而,街上的一句话是工会完全不安全。从最近没有写过的工会成员那里读取它的未定义行为。

所以我尝试了更多的C ++方法:

float ieee_float(uint32_t f)
{
  return *reinterpret_cast<float*>(&f);
}
  

错误:解除引用类型惩罚指针将破坏严格别名规则[-Werror = strict-aliasing]

我的下一个想法是&#34;拧紧它。为什么我要处理指针呢?&#34;并尝试过:

float ieee_float(uint32_t f)
{
  return reinterpret_cast<float>(f);
}
  

错误:从'uint32_t {aka unsigned int}'类型无效转换为'float'类型

有没有办法在不触发警告/错误的情况下进行转换?我正在使用-Wall -Werror使用g ++进行编译。我宁愿不接触编译器设置。

我标记了C,因为c解决方案是可以接受的。

2 个答案:

答案 0 :(得分:8)

在C ++中,正确的方式™是:

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

-O1及以上的GCC和Clang都会为此代码生成相同的程序集,并且会生成一个天真的reinterpret_cast<float &>(f)

答案 1 :(得分:1)

您有几个选项,如here所述:

  • 使用union解决方案:因为C11明确允许(如另一个答案所述)。
  • 不使用32位字的数组,而是使用8位字的数组(uint8_t),因为char类型可以别名为任何类型。