2011-05-09 112 views
2

樣本問題讓我們思考下面的代碼,並預測哪些將被函數funct_1打印出來:功能範圍和增加參數

void func_1(int i, int j) { 
    printf("i is %d, j is %d\n", i, j); 
} 
/* ... */ 
/* somewhere in the code, a call to func_1 */ 
int i = 30; 
func_1(i, i++); 
/* ... */ 

我認爲,當參數以這種形式傳遞他們在哪裏遞增,就不可能預測編譯器何時增加i。然而,解決方案是:

The values in the argument are passed as an attack to the function, hence 'j' receives 
a value '30' and then i receives the incremented value which is '31'. 

Output: i is 31, j is 30 

有人能解釋一下對某個函數的攻擊是什麼以及這是怎麼發生的?

回答

1

該解決方案通常是錯誤的。你是對的;代碼的行爲是未定義的。在一些編譯器上,答案可能是30和31;在別人身上,可能是30和30;在別人身上,可能是31歲和31歲;其他人可能會簡單地刪除硬盤上的所有文件(因爲未定義的行爲未定義)。幸運的是,在編譯器中,激進的,刪除所有痕跡的問題行爲相對不太可能。

對於某些特定平臺上的某些特定編譯器,解決方案可能是正確的。


其實,我認爲這是不可能得到31 jfunc_1() - 但產生30和30的操作順序是容易想象:中i值推兩次,然後我遞增,然後調用該函數。

+0

現在我徹底困惑。這個問題並沒有說明我們要承擔某個平臺,而是明確指出「我是31」而「j是30」。 =/ – raphnguyen 2011-05-09 02:34:37

+1

@raphnguyen:對不起,你很困惑。麻煩的是,這個問題不是很好,就像詢問未定義的行爲一樣。答案不是很好 - 說明福音至多是一種特定(但尚未說明)的編譯器展現的行爲。不幸的是,Mac OS X 10.6.7上GCC 4.6.0設置繁瑣給出了「警告:對'i'的操作可能未定義」,結果「我是31,j是30」,所以我沒有證明我的觀點。 – 2011-05-09 03:10:12

+1

@raphnguyen:我檢查了Solaris 10(SPARC);產生31/30。我檢查了HP-UX 11.23;產生30/30。我檢查了AIX 6.1;產生30/30。 – 2011-05-09 03:35:59

3

這是不可能的預測;編譯器以確定性的方式工作,即使在灰色地區覆蓋不到或未被規範覆蓋。用這個特定的編譯參數被從右向左推,並且在右參數被推後不久發生後增量。

+0

謝謝,但是爲什麼左對右是左對右?當我讀代碼時,在我看來,'i = 30'和增加'i'後,'j = 31'。 – raphnguyen 2011-05-09 02:27:46

+0

http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl – 2011-05-09 02:28:57