我试图弄清楚这段代码大约一个小时但仍然没有运气。
#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),当然得到了不同的结果。我也读过很多关于工会和事情的文章。我注意到当我从返回中删除0x7F800000时,结果将是相同的。我想知道u.i是如何生成的,显然它不是一些随机垃圾,但它也不是函数参数中的一个(1)。这里发生了什么,它是如何工作的?
答案 0 :(得分:2)
这实际上相当于了解浮点数如何在内存中表示。 (见IEEE 754)。
简而言之,32位浮点数将具有以下结构
关于联盟,回想一下联盟是一个计算机内存块,可以同时保存其中一种类型,所以声明:
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 000 000.请注意,我们已经放弃了领先的“1&#39;因为它总是假设在那里。
把这一切放在一起,我们有位模式:
4 = 0100 0000 1110 0000 0000 0000 0000 0000
现在,这里的最后一点是bit-wise和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
。