#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);
}
0
0.000000
0.500000
0
編譯用gcc 4.4.3 程序,錯誤代碼退出12
#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);
}
0
0.000000
0.500000
0
編譯用gcc 4.4.3 程序,錯誤代碼退出12
正如在其他答案中指出的,這是因爲格式字符串和參數類型之間的不匹配。
我猜你在這裏使用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
的,所以它似乎工作。
該結果並不令人驚訝,在第一%d你通過一個雙其中一個整數預計。
+1首先回答。 – 2010-08-01 19:36:48
@Billy ONeal,我以爲你應該upvote正確的答案... – strager 2010-08-01 19:37:23
@Strager:他們都是正確的答案;我把所有這些都提高了。只是想不出別的理由。 – 2010-08-01 19:38:51
是的。參數從可變參數列表中讀取,與讀取格式說明符的順序相同。
這兩個printf
語句都是無效的,因爲您使用的格式說明符預期爲int,但您只給它一個 float double。
但是爲什麼它的行爲在兩個陳述中都會改變? – blacktooth 2010-08-01 19:41:35
@blacktooth:不知道。當你調用未定義的行爲時,編譯器不需要做明智的事情。 – 2010-08-01 19:46:27
@比利我告訴那個問我同樣問題的人。 :D他告訴我這是一個面試問題! – blacktooth 2010-08-01 19:49:00
當你說在格式化字符串%d
,你必須通過的int
值作爲相應的參數。否則的行爲是不確定的,這意味着你的電腦可能會崩潰或外星人可能敲你的門。類似於%f
和double
。
生活學會了我總是投這樣的所有printf參數: const char * p =「stop」; int i = 7; printf(「Hello%s%d」,(const char *)p,(int)i); – danatel 2010-08-01 19:50:06
這也很危險。我寧願放棄這些強制轉換,讓編譯器檢查這些類型是否匹配。 GCC在這方面做得非常出色。在C中,你永遠不能確定'(const char *)'不會意外地將一個'int'轉換爲一個指針。從句法上講,這是可能的。 – 2010-08-01 20:56:09
你在做什麼是不確定行爲。你看到的是巧合的; printf
可以寫任何東西。
在給出printf
參數時,您必須匹配確切類型。你可以例如演員:
printf("\n%d\n%f", (int)(x/y), x/y);
printf("\n%f\n%d", x/y, (int)(x/y));
http://en.wikipedia.org/wiki/Format_string_attack
東西與我的問題。支持馬修的回答。
*現在* *很有趣... – dmckee 2010-08-01 19:34:39
我有一種衝動來解決這個問題 - 只是在字符串的開頭使用「\ n」。否則,這就是爲什麼始終保持編譯器警告激活的好主意。 – Dummy00001 2010-08-01 19:48:57
@Dummy:同意換行符,但是我一直無法得到'gcc'來抱怨任何接受'main'缺少正確指定的返回類型的東西。 – dmckee 2010-08-01 19:51:39