执行环境:32位机小端序 Linux version 2.6.18-238.el5 (mockbuild@ls20-bc2-13.build.redhat.com) (gcc version 4.1.2 20080704 (Red Hat 4.1.2-50))
遇到一个问题,误把int数据直接强制转换为float型数据来用,得出的结果完全不认识,看来需要仔细分析一下float及int数据在内存里具体是怎么格式存储的,只有这样才能搞明白中途发生了什么,导致出错。
float fv=52.5;
char *cp=&fv;
printf("%x,%x,%x,%x\n",*cp,*(cp+1),*(cp+2),*(cp+3));
执行输出:0,0,52,42
二进制显示既: 0000 0000 0000 0000 0101 0010 0100 0010
既然内存里存储格式如此,那么如何转化为float型52.5的呢?
查阅float数据格式:SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM
S:符号位,占1位空间
E:指数位,占8位空间,其值为真实的二进制指数加127得出,为什么加127是IEEE定的。你可以去问他们。
M:底数位,占24位,但实际上值存了23位,小数点前默认为1,所以省出来1位。
小端序机器可知
S=0 --->0代表正,1代表负
E=100 00100 --->132-127=5,真实的指数为5
M=101 0010 0000 0000 0000 0000 --->小数点固定为1则底数为1.101 0010 0000 0000 0000 0000
好了现在已经将数据按照float格式界定完毕,接下来就是如何转化验证是不是预期所示的52.5
将二进制转为十进制数据:1*2^5+1*2^4+0*2^3+1*2^2+0*2^1+0*2^0+1*2^(-1)+0*.....0*2^(-19)=32+16+4+0.5=52.5
结果如预期。
通过分析可知float的数据存储与int数据存储策略是完全不同的,如人为的将int ivar误当做float 数据用那么,ivar里本身原有的数据位会相应的分配为 S位,E位及M位,结果可想而知。完全就乱了。编译器很傻的这时候。
有个特例既 float 0的存储 指数及底数均为0,但2^0=1,不符合SEM公式,当做特例处理即可,不影响通用性。