我试图找出此代码大约一个小时,但仍然没有运气。
#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/