1 2 3 4 5 6 7 8 9 10 11 12 int main () { int n=9 ; float *pFloat =(float *)&n; printf ("n的值为:%d\n" ,n); printf ("*pFloat的值为:%f\n" ,*pFloat); *pFloat=9.0 ; printf ("num的值为:%d\n" ,n); printf ("*pFloat的值为:%f\n" ,*pFloat); return 0 ; }
思考下这段代码输出的值是什么?
可能你会感到好奇:
我明明&n后强转成了float类型,为什么还会输出0.000000呢?
为什么* pFloat=9.0,以%d的形式输出会得到这么大的一个数呢?
别急,我慢慢解释。
首先我们需要知道浮点型的数据在内存中是如何存储的。
浮点型的数据是根据国际标准“IEEE 754”来存储的,标准规定:每个浮点数V=(-1)^S* M*2^E
当S=0时,浮点数为正数
当S=1时,浮点数为负数
那么M与E又代表什么意思呢?
假设我们有一个浮点数“5.5”,把它转换成二进制的形式就是:101.1,此时它的S=0,M=1.01,E=2。
(就好比科学计数法,5500=5.5*10^3,只不过浮点型V=(-1)^S * M * 2^E是把科学计数法的10换成了2。)
回到正题,M就是将浮点数转换成二进制再转换成类似于科学计数法的形式时,5.5的部分,E就是小数点的位移量,
同时,计算机又根据32为浮点型(float)与64位浮点型(double)将存储方式分类两类:
32位浮点型:第一位位符号位(s),往后8 bit表示E,剩下23 Bit表示M
64位浮点型:第一位表示符号位,往后11 bit表示E,剩下52 bit表示M。
关于M:
M,的取值范围:M大于等于1,小于2。
也就是说,M是默认存在一个1的,所以,为了节省一位有效数字,我们在把M存储到内存中时,只会存储小数部分,当要使用该浮点型的数时,提取M,只需要在前面加上一个1就行。假设是一个32位的浮点数,以这样的方式存储,原本只能存放23位有效数字,现在就能存放24位有效数字了(存放到内存中的小数部分(23位)与默认的1,一共24位)
关于E:
上面我们说到,V的公式类似于科学计数法,但是在科学计数法里,E的值可以为负数;但是在V公式中,E是一个无符号整型,它只能为正数,所以,为了防止出现负数的情况,在计算机把E存入到内存中时,会让E加上一个中间值。
32位的浮点型中间值为127
64位的浮点型中间值为1023
比如上面提到的V=5.5=101.1=(-1)^0* M *2^2;
E=2,加上中间值=129,再转换成二进制形式:1000 0001。
如果要取出来,也很简单,让E减去中间值就行了。
但是在提取E时,会出现三种情况:
E全为0的情况
E全为1的情况
E不是全为1也不是全为0的情况(正常情况)
E全为0的情况 :(假设是32位浮点数)
1 s: 0 E: 00000000 M: 00000000000000000000000
此时E是存储在内存中的,E=0,我们知道E存储到内存中时要加上中间值,前面已经知道了32位浮点数的中间值是127,当E为多少时,加上中间值会等于0?答案是:-127
所以 : v=(-1)^S* M*2^E,此时不管S与M等于多少,最终V都是一个接近于0的数。
E全为1的情况 :
1 s: 0 E: 11111111 M: 00000000000000000000000
此时E是存储在内存中的,E转换成十进制是255,我们知道E存储到内存中时要加上中间值,前面已经知道了32位浮点数的中间值是127,当E为多少时,加上中间值会等于255?,答案是:128。
所以 : v=(-1)^S* M*2^E,此时不管S与M等于多少,最终V都是一个非常大的数。
E不是全为1也不是全为0的情况(正常情况) :
正常情况就不赘述了。当你看完了前面的内容,这种情况也就能自己去推算了。
现在我们在回到前面的问题:
1 2 3 4 5 6 7 8 9 10 11 12 int main () { int n=9 ; float *pFloat =(float *)&n; printf ("n的值为:%d\n" ,n); printf ("*pFloat的值为:%f\n" ,*pFloat); *pFloat=9.0 ; printf ("num的值为:%d\n" ,n); printf ("*pFloat的值为:%f\n" ,*pFloat); return 0 ; }思考下这段代码输出的值是什么?
当面把&强转成浮点型时,9=(-1)^S* M *2^E;
S=0、E=00000000、M=00000000000000000001001。
所以最后输出:
1 printf ("*pFloat的值为:%f\n" ,*pFloat);
值为:0.000000
在当我们给*pFlota赋值9.0时;
9.0=(-1)^S* M* 2^E;
S=0、M=001、E=3,
转换成二进制:0 10000010 00100000000000000000000,再转换成十进制就等于:1091567616