2012-06-16 38 views
5

當我運行此代碼時,輸​​出爲11,10。在函數參數中使用後遞增

爲什麼地球上會這樣?有人能給我一個解釋,希望能啓發我嗎?

由於

#include <iostream> 
using namespace std; 

void print(int x, int y) 
{ 
    cout << x << endl; 
    cout << y << endl; 
} 
int main() 
{ 
    int x = 10; 
    print(x, x++); 
} 
+1

我得到一個非常顯着的錯誤/上GCC 4.7.0警告(-Werror):'錯誤:上的 'x' 可以是不明確的操作[-Werror =序列點]'。將警告級別提高總是很好的。 – chris

+0

@ acidzombie24,我看到你編輯了我的文章,特別是打印中的函數參數。這是什麼原因?將第二個參數從「x ++」更改爲「x + 1」會使整個帖子的目的失敗,不是嗎? – ordinary

+0

哦對不起。這是一個巨大的疏忽。我正在玩一些代碼,我忘了把++改爲+1。比數字和格式困擾我,我複製/粘貼我的代碼。那個+1 ...哎呀。我改回來了。 (我希望你能編輯你自己的帖子,所以如果你再看到這樣的錯誤,也許你可以這樣做) – 2012-06-28 07:41:03

回答

11

C++ standard狀態(在第16年9月1日的說明):

Value computations and side effects associated with the different argument expressions are unsequenced.

換句話說,它是未定義和/或編譯器相關何種順序之前其值被傳遞到的參數進行評估在功能。因此,在一些編譯器(首先評估左邊的參數)中,代碼會輸出10, 10,而其他(首先評估正確的參數)代碼會輸出11, 10。一般來說,你不應該依賴未定義的行爲。

爲了幫助你理解這一點,設想每個參數表達式在函數被調用之前都要進行評估(不是說它實際上是如何工作的,它只是一個簡單的方法來考慮它,它會幫助你理解測序):

int arg1 = x;  // This line 
int arg2 = x++;  // And this line can be swapped. 
print(arg1, arg2); 

C++標準說這兩個參數表達式是不確定的。因此,如果我們用這樣的單獨線條寫出參數表達式,它們的順序不應該很重要,因爲標準說它們可以按任何順序進行評估。一些編譯器可能會在訂單評估它們上面,其他人可能交換他們:

int arg2 = x++;  // And this line can be swapped. 
int arg1 = x;  // This line 
print(arg1, arg2); 

這使得它很明顯的是如何arg2可容納值10,而arg1持有價值11

您應該在代碼中始終避免這種未定義的行爲。

+0

我第一次見到有人在他們的答案中實際鏈接到了標準,而不是問題在哪裏得到它。 – chris

+0

謝謝,我現在完全明白!會upvote,但我沒有足夠的業力點或任何。 – ordinary

+1

要明確這不是未定義行爲,而只是未指定行爲。兩者明顯不同。 –

4

X ++是一個功能參數,並且它們可以在一個未指定的順序,這意味着其行爲是未定義和不便攜式(或合法)來評價。

+0

其實,這不僅僅是未指定的行爲,更重要的是它是未定義的行爲。請檢查我的答案。 –

0

我相信這與最後一個參數先進入的函數調用堆棧有關。所以x ++是你的y,x是print()中的本地x。

6

在整個聲明:

print(x, x++); 

導致一個未定義行爲。一旦程序有了未定義的行爲,它就不再是一個有效的C++程序,並且從字面上看,任何行爲都是可能的。因此找到這樣的程序的推理是毫無意義的。


Why is this Undefined Behavior?

讓評估一步點程序步驟,我們可以毫無疑問地證明,它會導致未定義行爲

的參數的函數的評價順序是未指定[參考1]

未指定意味着執行被允許,因爲它期望和不要求記錄關於它的細節以實現該特定功能。

應用上述規則,以你的函數調用:

print(x, x++); 

實現可以評估這個爲:左到右

  • 右至左或
  • 任何神奇的秩序(在多於兩個函數參數的情況下

簡而言之,您不能依賴某個實現來遵循任何特定順序,因爲它不是按照C++標準要求的。

在C/C++中,不能讀取或寫入到一個變量不止一次而沒有中間sequence point[參考文獻2]。如果這樣做它導致的任一是否一個未定義Behavior.Irrespective在所述函數中首先評估參數,它們之間沒有序列點,僅在評估所有函數參數[參考文獻3]之後存在序列點。

在這種情況下,x正在被訪問而沒有插入序列點,因此它會導致未定義的行爲。

簡單地說,最好是寫不援引該不確定的行爲,,因爲一旦你這樣做,你不能指望從這樣一個方案的任何具體行爲的任何代碼。


[參考1]C++ 03標準§5.2.2.8
帕拉8:

[...] The order of evaluation of function arguments is unspecified. [...]


[參考文獻2]C + +03 5表達式[expr]:
第4段:

....
Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.


[參考文獻3]C++ 03 1.9程序執行[前奏。執行]:
帕拉17:

When calling a function (whether or not the function is inline), there is a sequence point after the evaluation of all function arguments (if any) which takes place before execution of any expressions or statements in the function body.