首页 文章

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

提问于
浏览
3

我从网络接收缓冲区,该缓冲区被转换为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]

我的下一个想法是“搞砸它 . 为什么我要处理指针呢?”并尝试过:

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

错误:从'uint32_t '类型无效转换为'float'类型

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

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

2 回答

  • 1

    您有几种选择,如here所述:

    • 使用 union 解决方案:因为C11明确允许(如另一个答案中所述) .

    • 使用8位字数组(uint8_t)而不是使用32位字数组,因为 char 类型可以别名为任何类型 .

  • 7

    在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) .

相关问题