2010-03-10 86 views
3

考慮以下代碼:如何在函數調用中評估參數?

void res(int a,int n) 
{ 
    printf("%d %d, ",a,n); 
} 

void main(void) 
{ 
    int i; 
    for(i=0;i<5;i++) 
     res(i++,i); 
    //prints 0 1, 2 3, 4 5 

    for(i=0;i<5;i++) 
     res(i,i++); 
    //prints 1 0, 3 2, 5 4 
} 

望着輸出,似乎參數不從右到左每一次評估。到底發生了什麼?

回答

7

未指定函數調用中自變量的求值順序。編譯器可以按照它可能決定的順序對它們進行評估。

C99標準6.5.2.2/10「函數調用/語義」:

功能標誌的評估順序,實際參數中的實際參數, 子表達式是不確定的,但在實際調用之前有一個序列點 。

如果你需要確保一個特定的順序,使用臨時工是通常的解決方法:

int i; 
for(i=0;i<5;i++) { 
    int tmp = i; 
    int tmp2 = i++; 

    res(tmp2,tmp); 
} 

更重要的是(因爲它導致不確定的行爲,不只是不確定的行爲)是可以大體在表達式中多次使用操作數來增加/減少運算符。這是因爲:

在上一個和下一個序列點之間,一個對象應該通過評估一個表達式對其存儲值進行至多一次修改。此外,先驗值只能讀取以確定要存儲的值。 (6.5/2「表達式」)

3

按照標準:參數評估的順序是未指定的。此外,請注意,參數評估時沒有序列點(英里數帖子)。因此,修改同一個變量作爲參數的一部分,不止一次會引起未定義的行爲。這是一個FAQ 3.2。您發佈的代碼因此具有模糊的行爲。

標準爲什麼沒有指定這可能是令人驚訝的:簡單的原因是這允許編譯器執行一些優化。 (請參閱與GOTW #56的Q2相關的討論。)

但是在大多數實現中,這取決於所謂的調用約定。調用約定不僅決定了順序,而且還強制清除堆棧或者調用者或被調用者的責任。

另請注意,main始終返回int