我试图找出此代码大约一个小时,但仍然没有运气。

#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),当然得到了不同的结果。我也读了很多关于工会和东西的文章。我注意到,当我从return删除0x7F800000时,结果将是相同的。我想知道u.i是如何生成的,显然这不是一些随机垃圾,也不是函数参数中的一(1)。这是怎么回事,它如何工作?

最佳答案

这实际上是对如何在内存中表示浮点数的理解。 (请参阅IEEE 754)。

简而言之,一个32位浮点数将具有以下结构


第31位将是总数的符号位
位30-23将为该数字的指数,偏差为127
位22-0将代表数字的小数部分。对此进行了规范化,以使小数点(实际上是二进制)点之前的数字为1。


关于联合,请回想一下,联合是计算机内存的一块,可以同时容纳一种类型,因此声明:

   union un
   {
        float f;
        int   i;
   };


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

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

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

    4 = 0000 0000 0000 0000 0000 0000 0000 0111


现在我们需要对此进行归一化,即以升为2的幂表示一个数字;

    1.11 x 2^2


在这里,我们需要记住,每个2的幂都将二进制点右移(类似于处理10的幂)。

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


该数字的总符号为正,因此总符号位为0。
指数为2,但我们将指数乘以127。这意味着-127的指数将存储为0,而127的指数将存储为255。因此,我们的指数字段将为129或1000 0001。
最后,我们的归一化数字将是1100 0000 0000 0000 0000 000000。请注意,我们删除了开头的“ 1”,因为它始终假定在那里。
放在一起,我们将其作为位模式:

4 = 0100 0000 1110 0000 0000 0000 0000 0000


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

因此,您的程序只是打印出浮点数的有偏指数。举个例子,

    #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/

10-10 01:54