Q: 如下代碼的輸出結果是多少?
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
printf("%d\n", 5.0f);
return 0;
}
A: %d本來對應的是整形,實際參數傳入浮點數5.0f. 5.0f會強制轉換成整形5嗎?
對于此類問題, 最佳的分析手法是從原理和彙編出發, 不論什麼格式都可以分析出.
首先, printf是如何處理格式串的, %d格式串會被printf解析出, 并從參數中取一個整數,注意,此整數是強制拿sizeof(int)位元組的資料,并沒有對參數做可适配轉換(比如浮點數去掉小數點變成整數之類的友好轉換)。
printf 格式串的處理: printf 内部原理和實作 (你想知道的C語言 1.2)
是以,其實5.0f是啥不重要,重要的是5.0f被存儲的資料二進制形式是什麼.
按照浮點數的IEEE754标準的轉換算法,5.0f将被轉換成0x40A00000. 是以,上面輸出的整數應該就是1084227584.(注意此處的結論不一定是對的!)
5.0f是被轉換成0x40A00000, 可以用如下代碼驗證:
/*
Xi Chen([email protected])
cxsjabcabc
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
void dump_data(void *data, int bytes)
{
int i;
unsigned char *p;
p = (unsigned char *)data;
for (i = 0; i < bytes; ++i) {
printf("%x ", p[i]);
}
printf("\n");
}
int main(int argc, char *argv[])
{
float d = 5.0f;
dump_data(&d, sizeof(d));
return 0;
}
https://github.com/cxsjabc/basic/blob/dev/c/_topics/printf/parse_data.c
Q: 實際的運作結果看起來不是上面的數字,而且每次執行還會變動?
A: 彙編代碼如下:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL90UbZhmTtlFawJzY04kMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL2YDN0ADO1AjMwEzNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
可以看到參數5.0f被放到了xmm寄存器中, 此為儲存浮點數參數的寄存器. 但是printf内部實作會從堆棧強制找sizeof(int)位元組資料,這将是不确定的資訊.
在不适用xmm寄存器,而是用堆棧傳遞參數的編譯器環境下,才會得到1084227584.
作者: 陳曦
環境: MacOS 10.14.5
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.6.0
轉載請注明出處