天天看点

printf以%d形式输出浮点数的问题

float value = 1.0;
printf("value_int = %d\n", value);
           

  对于上面的代码,会输出什么结果呢?( 结果是0,当然这跟你的计算机是大端还是小端有关,大小端分析一样,这里是以小端为例)是不是觉得很奇怪,value的浮点数表示形式是 0x3F800000,如果以整形输出,应该也是这个值的十进制表示才对的。

单精度浮点数表示是:1位符号,8位阶码,23位尾数: 1.0的符号位是0,注意1.0的整数位1省略了,所以尾数全是0,而阶码是移码表示,所以是1+127,参考 。 双精度浮点数表示是:1位符号,11位阶码,52位尾数:如果是double value,则value的表示形式是 0x3FF0000000000000 关于浮点数的机器表示参考: http://zh.wikipedia.org/wiki/IEEE_754 

分析上面代码的汇编实现:(这里是VS下的反汇编代码,关注标红部分及下面的解释就行) float value = 1.0;汇编代码如下: 004113BE   fld1          //向浮点器特殊寄存器st7(64位)中初始化值为1的浮点数(双精度)      004113C0   fstp        dword ptr [value]   //从浮点器特殊寄存器st7中载入数值到value中,注意这里是dword(32位),作了双精度到单精度的转换   printf("value_int = %d\n", value);汇编代码如下: 004113C3   fld         dword ptr [value]  //向浮点器特殊寄存器st7(64位)中存入单精度value 004113C6  mov         esi,esp  004113C8  sub         esp,8  004113CB   fstp        qword ptr [esp] //从浮点器特殊寄存器st7中载入数值(value的双精度)到esp指向的地址中,注意这里是qword(64位),所以不用转换  004113CE  push        offset string "value_int = %d\n" (415800h)  004113D3  call        dword ptr [__imp__printf (4182BCh)]  004113D9  add         esp,0Ch

上面的代码把1的双精度值压入了栈中,而我的计算机又是小端的,那么内存从从低到高字节依次是 00 00 00 00 00 00 F0 3F(即0x3FF0000000000000以字节为单位倒置)

当printf检测到%d要输出整形时,取到的值是00 00 00 00,所以这就不难理解为什么结果是0了。如果是大端,那么输出0x3FF00000的十进制值。

如果对printf实现不是很了解,可以参考http://blog.csdn.net/fzp218/article/details/7375427

总结: 适当知道点汇编还是挺重要的,像这种在高级语言层面看不清的问题,一看汇编就明了了。