2010-08-01 29 views
4
#include<stdio.h> 
main() 
{ 
    float x=2; 
    float y=4; 
    printf("\n%d\n%f",x/y,x/y); 
    printf("\n%f\n%d",x/y,x/y); 
} 

輸出:printf()取決於格式說明符的順序嗎?

0 
0.000000 
0.500000 
0 

編譯用gcc 4.4.3 程序,錯誤代碼退出12

+0

*現在* *很有趣... – dmckee 2010-08-01 19:34:39

+2

我有一種衝動來解決這個問題 - 只是在字符串的開頭使用「\ n」。否則,這就是爲什麼始終保持編譯器警告激活的好主意。 – Dummy00001 2010-08-01 19:48:57

+0

@Dummy:同意換行符,但是我一直無法得到'gcc'來抱怨任何接受'main'缺少正確指定的返回類型的東西。 – dmckee 2010-08-01 19:51:39

回答

15

正如在其他答案中指出的,這是因爲格式字符串和參數類型之間的不匹配。

我猜你在這裏使用x86(根據觀察結果)。

參數在棧上傳遞,而x/y(儘管類型爲float)將作爲double傳遞給可變參數函數(由於類型「提升」規則)。

int是一個32位的值,而double是一個64位的值。

在這兩種情況下,您都通過x/y(= 0.5)兩次。該值的表示形式爲64位double,爲0x3fe0000000000000。作爲一對32位字,它被存儲爲0x00000000(最不重要的32位),然後是0x3fe00000(最重要的32位)。因此,在棧上的參數會被printf()所看到,像這樣:

0x3fe00000 
0x00000000 
0x3fe00000 
0x00000000 <-- stack pointer 

在第一個你的兩種情況,%d導致第一個32位的值,0x00000000,被彈出並打印。 %f彈出接下來的兩個32位值,0x3fe00000(64位double的最低有效32位),然後是0x00000000(最重要)。結果爲0x000000003fe00000的64位值,解釋爲double,是一個非常小的數字。 (如果將格式字符串中的%f更改爲%g,則會看到它幾乎爲0,但不完全)。

在第二種情況下,%f正確彈出第一double,和%d彈出0x00000000一半的第二double的,所以它似乎工作。

2

該結果並不令人驚訝,在第一%d你通過一個雙其中一個整數預計。

+0

+1首先回答。 – 2010-08-01 19:36:48

+1

@Billy ONeal,我以爲你應該upvote正確的答案... – strager 2010-08-01 19:37:23

+0

@Strager:他們都是正確的答案;我把所有這些都提高了。只是想不出別的理由。 – 2010-08-01 19:38:51

4

是的。參數從可變參數列表中讀取,與讀取格式說明符的順序相同。

這兩個printf語句都是無效的,因爲您使用的格式說明符預期爲int,但您只給它一個 float double。

+0

但是爲什麼它的行爲在兩個陳述中都會改變? – blacktooth 2010-08-01 19:41:35

+4

@blacktooth:不知道。當你調用未定義的行爲時,編譯器不需要做明智的事情。 – 2010-08-01 19:46:27

+0

@比利我告訴那個問我同樣問題的人。 :D他告訴我這是一個面試問題! – blacktooth 2010-08-01 19:49:00

7

當你說在格式化字符串%d,你必須通過int值作爲相應的參數。否則的行爲是不確定的,這意味着你的電腦可能會崩潰或外星人可能敲你的門。類似於%fdouble

+1

生活學會了我總是投這樣的所有printf參數: const char * p =「stop」; int i = 7; printf(「Hello%s%d」,(const char *)p,(int)i); – danatel 2010-08-01 19:50:06

+0

這也很危險。我寧願放棄這些強制轉換,讓編譯器檢查這些類型是否匹配。 GCC在這方面做得非常出色。在C中,你永遠不能確定'(const char *)'不會意外地將一個'int'轉換爲一個指針。從句法上講,這是可能的。 – 2010-08-01 20:56:09

3

你在做什麼是不確定行爲。你看到的是巧合的; printf可以寫任何東西。

在給出printf參數時,您必須匹配確切類型。你可以例如演員:

printf("\n%d\n%f", (int)(x/y), x/y); 
printf("\n%f\n%d", x/y, (int)(x/y));