将uint32_t铸造到c/c 中浮动

bitwise casting uint32_t to float in C/C++

本文关键字:uint32      更新时间:2023-10-16

我正在从网络中接收一个缓冲区,该网络被转换为32位单词的数组。我有一个单词,该单词被我的接口文档定义为IEEE-754浮动。我需要从缓冲区中提取这个单词。在不调用转换的情况下,很难从一种类型到另一种类型。这些位已经遵守IEEE-754浮点标准,我不想重新安排任何位。

我的第一次尝试是将uint32_t的地址投放到void*,然后将void*转换为float*,然后将其解释为float

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

错误:删除类型 - 划分指针将破坏严格确定的规则[-werror = strict-oliasing]

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

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-oliasing]

我的下一个想法是"拧"它。为什么我无论如何都要处理指针?"刚刚尝试:

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

错误:从类型'uint32_t {aka unsigned int}'type" float'

(

有没有触发警告/错误的方法进行转换的方法?我正在使用-Wall -Werror使用G 编译。我宁愿不触摸编译器设置。

i标记了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;
}

-O1及更高版本的GCC和Clang为此代码生成相同的组件和幼稚的reinterpret_cast<float &>(f)(但后者是未定义的行为,在某些情况下可能不起作用(。

没有C/C 语言。它们是具有不同规则的不同语言。C中的有效方法是使用联合,但在C 中不允许使用联合。参见

  • 工会和类型 - 束缚
  • 通过C99中未指定的工会进行了键入,并且是否在C11中指定?

在较旧的C 标准中,您必须使用std::memcpy。即使是reinterpret_cast,类型的双关语都会调用未定义的行为,因此不允许。在C 20中,完全为此目的创建了一种称为std::bit_cast的新型演员类型

float ieee_float(uint32_t f)
{
  return std::bit_cast<float>(f);
}

另请参见:

  • 如何将浮子插入flot到int,反之亦然是什么?
  • 在C 中进行键入的现代,正确的方法是什么?

您有几个选项,如下所示:

  • 使用union解决方案:由于C11明确允许(如其他答案中所述(。
  • 而不是使用32位单词的数组,而是使用8位单词(UINT8_T(的数组,因为char类型可以与任何类型的类型相称。