c - 与 union 产出作斗争

标签 c bit-manipulation unions

我花了大约一个小时试图弄清楚这段代码,但仍然没有成功。

#include <stdio.h>
#include <stdlib.h>

int f(float f)
{
    union un {float f; int i;} u = {f};

    return (u.i&0x7F800000) >> 23;
}

int main()
{
    printf("%d\n", f(1));

return 0;
}

我不明白这是如何工作的,我尝试过 f(1)、f(2)、f(3)、f(4),当然得到了不同的结果。我还读了很多关于 union 之类的东西。我注意到,当我从返回中删除 0x7F800000 时,结果将是相同的。我想知道 u.i 是如何生成的,显然它不是一些随机垃圾,但它也不是函数参数中的一(1)。这是怎么回事,它是如何工作的?

最佳答案

这实际上相当于理解 float 在内存中的表示方式。 (参见 IEEE 754)。

简而言之,32位 float 将具有以下结构

  • 第 31 位将是总数的符号位
  • 第 30 - 23 位将是数字的指数,偏差为 127
  • 位 22 - 0 将表示数字的小数部分。这是标准化的,小数点(实际上是二进制)之前的数字是 1。

关于 union ,回想一下, union 是一 block 计算机内存,可以同时保存其中一种类型,因此声明:

   union un
   {
        float f;
        int   i;
   };

正在创建一个32位内存块,可以在任何给定时间保存 float 或整数。现在,当我们使用浮点参数调用该函数时,该数字的位模式将被写入 un 的内存位置。现在,当我们使用 i 成员访问 union 体时,位模式将被视为整数。

因此,32位 float 的一般布局为seee eeee efff ffff ffff ffff ffff ffff,其中s代表符号位, e 指数位和 f 分数位。好吧,有点胡言乱语,希望一个例子能有所帮助。

要将 4 转换为 IEEE float ,首先将 7 转换为二进制(我已将 32 位数字拆分为 4 位半字节);

    4 = 0000 0000 0000 0000 0000 0000 0000 0111

现在我们需要对其进行标准化,将其表示为 2 次方的数字;

    1.11 x 2^2

这里我们需要记住,每次 2 的幂都会将二进制小数点向右移动(类似于处理 10 的幂)。

由此,我们现在可以生成位模式

  1. 数字的整体符号为正,因此整体符号位为 0。

  2. 指数为 2,但我们将指数偏置为 127。这意味着 -127 的指数将存储为 0,而 127 的指数将存储为 255。因此我们的指数字段将是129 或 1000 0001。

  3. 最后,我们的标准化数字将是 1100 0000 0000 0000 0000 000 000。请注意,我们已经删除了前导“1”,因为它始终假定在那里。

  4. 将所有这些放在一起,我们得到位模式:

    4 = 0100 0000 1110 0000 0000 0000 0000 0000

现在,这里的最后一点是逐位的,并且 0x7F800000 如果我们 二进制写出的是 0111 1111 1000 0000 0000 0000 0000 0000,如果我们将其与 IEEE float 的一般布局进行比较,我们会发现我们使用掩码选择的是指数位,然后我们将其向左移动 23 位。

所以你的程序只是打印出 float 的有偏差指数。举个例子,

    #include <stdio.h>
    #include <stdlib.h>

    int f(float f)
    {
         union un {float f; int i;} u = {f};

         return (u.i&0x7F800000) >> 23;
    }

    int main()
    {
         printf("%d\n", f(7));
         return 0;
    }

给出了 129 的输出,正如我们所期望的。

关于c - 与 union 产出作斗争,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40203449/

相关文章:

c - 哪个是冒泡排序?

c - 逻辑运算符

c++ - 从连续的单词序列中提取任意范围的位的最有效方法是什么?

从符号大小转换为二进制补码

memory - 有没有更安全的方法使用联合在整数和 float 之间进行转换?

c++ - 在 C/C++ 中从 TCP 套接字读取的正确方法是什么?

c - C 中的位操作和标志测试

c++ - 以下 union 中的值是如何分配的?

c - 如何在运行时区分 c 中的 union 成员

c - 这个基本的 strcat 实现有什么问题?