2014-03-06 42 views
5

我發現了一個很奇怪的,我測試此代碼:C++ - 奇怪的事情,輸入得到扭轉

#include <iostream> 
using namespace std; 

int main() { 
    int i=0, a[5]; 
    cin>>a[i++]>>a[i++]>>a[i++]; 
    for(int j=0; j<i; j++){ 
     cout<<a[j]<<endl; 
    } 
} 

有了這個輸入:

1 
2 
3 

,並得到了輸入扭轉這樣的:

3 
2 
1 

我以爲它的輸出應該和這段代碼一樣:

#include <iostream> 
using namespace std; 

int main() { 
    int i=0, a[5]; 
    cin>>a[i++]; cin>>a[i++]; cin>>a[i++]; 
    for(int j=0; j<i; j++){ 
     cout<<a[j]<<endl; 
    } 
} 

以前有人遇到過這個嗎?謝謝。

-Edit-

感謝所有的答案!

+1

未定義的行爲! – hivert

回答

5
cin>>a[i++]>>a[i++]>>a[i++]; 

僅僅是

cin.operator>>(a[i++]).operator>>(a[i++]).operator>>(a[i++]); 

現在語法糖,三個電話operator>>肯定執行由左到右,但三個參數a[i++]可以以任何順序評估。讓我們調用的參數xyz

cin.operator>>(x).operator>>(y).operator>>(z); 

您可能希望編譯器來替代xyz如下:

int& x = a[i]; 
i++; 
int& y = a[i]; 
i++; 
int& z = a[i]; 
i++; 

但事實上,編譯器給予更多的自由。在你的情況下,選擇:

int& z = a[i]; 
i++; 
int& y = a[i]; 
i++; 
int& x = a[i]; 
i++; 

正如詹姆斯·觀世所指出的,它也可以選擇:

int& x = a[i]; 
int& y = a[i]; 
int& z = a[i]; 
i++; 
i++; 
i++; 
+0

實際上,如果我們不確定的行爲,編譯器是免費的做任何希望的事情,包括生成崩潰的代碼。 (G ++執行此在某些情況下,當它識別未定義的行爲。)更可能地,編譯器可以做一些相當於'INT&X = A [1],&Y = A [1],&Z = A [1];我+ = 3;'。 –

+0

@JamesKanze謝謝 – fredoverflow

9

這感覺就像未定義行爲和編譯器相關的:

cin>>a[i++]>>a[i++]>>a[i++]; 

(大師,請糾正我,如果我錯了)

+0

我不是主人,但你是正確的,+1 – Bathsheba

+0

這是未定義的行爲。我不確定在這裏使用表達式「依賴於編譯器」,因爲這聽起來更像是「實現定義」(這意味着不同的實現可能做不同的事情,但他們必須記錄它)。特別是,這裏的結果可能會根據優化標誌,甚至周圍的語句中的代碼而有所不同。 –

9

聲明cin>>a[i++]>>a[i++]>>a[i++];的行爲實際上是不確定。這是因爲沒有序列點

你不知道什麼時候i會增加,因此你的輸出並不令人驚訝。

http://en.wikipedia.org/wiki/Sequence_point

+1

對運營商的呼叫不要引入序列點嗎? – juanchopanza

+0

@juanchopanza是的,但是在調用第一個'operator >>'的時候,已經評估過的'a [i ++]'參數的數量介於1和3之間。 – fredoverflow

+0

@FredOverflow這不會使行爲*未指定*? – juanchopanza

2

當你修改並使用相同的語句中的變量,這導致不確定的行爲。 我修改了3次,並在下面的語句中訪問了3次。

cin>>a[i++]>>a[i++]>>a[i++]; 

我猜下面的代碼會正常工作。

#include <iostream> 
using namespace std; 
int main() { 
    int i=0, a[5]; 
    cin>>a[0]>>a[1]>>a[2]; 

    i=3; 

    for(int j=0; j<i; j++){ 
    cout<<a[j]<<endl; 
} 
} 
1

正如已經被說的代碼是未定義行爲,因爲功能評價的順序沒有指定參數,因爲應用後增量運算符的副作用不是以確定性方式排序的。

不過我會解釋一下結果。

表達

cin>>a[i++]>>a[i++]>>a[i++]; 

相當於followiung表達式,如果我們將使用函數表示法

cin.operator >>(a[i++]).operator >>(a[i++]).operator >>(a[i++]); 

未指定的函數參數評價的順序。所以一些編譯人員從右向左評估論點,而其他人則從左向右。

很明顯,您的編譯器從右到左評估函數參數。首先是評估權的說法最起作用

cin.operator >>(a[i++]).operator >>(a[i++]).operator >>(a[0]); 

的論證評估後,編譯器應用的副作用。我等於1,則編譯evaluares第二函數的參數,你會得到

cin.operator >>(a[i++]).operator >>(a[1]).operator >>(a[0]); 

,最後評估後的第一個函數調用的參數會有

cin.operator >>(a[2]).operator >>(a[1]).operator >>(a[0]); 

和可變我將等於3。

然而作爲函數參數評估順序正如我所說的也不指定其他編譯器可以代表該表達作爲

cin.operator >>(a[0]).operator >>(a[1]).operator >>(a[2]); 

所以結果可能會不同,程序的行爲是不確定的。