天天看點

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

總結: 适當知道點彙編還是挺重要的,像這種在進階語言層面看不清的問題,一看彙編就明了了。