2016-02-17 23 views
1

int n6 = n1 + ++n1;這樣的陳述是未定義的行爲,因爲它們違反了排序規則。但是,如果它們違反了序列規則,爲什麼編譯器不會給出一個嚴重錯誤?其他的例子:爲什麼編譯器不執行排序規則?

i = ++i + i++; // undefined behavior 
i = i++ + 1; // undefined behavior (but i = ++i + 1; is well-defined) 
f(++i, ++i); // undefined behavior 
f(i = -1, i = -1); // undefined behavior 

似乎在所有這些情況下,標準明確地說,這是不確定的行爲,所以它可以很容易地說:「節目是形成不良的」,這通常會導致很難診斷。

+1

應該編譯能夠[this](http://coliru.stacked-crooked.com/a/f11297b5b6e064c8)出來嗎?這是同樣的事情,但很難診斷。 – NathanOliver

+0

硬錯誤是未定義行爲的有效結果,因此使其成爲UB允許編譯器拒絕它,如果它們能夠檢測到它(例如,用'-Werror = sequence-point'或類似的方法) –

+1

@JonathanWakely一個硬錯誤只是在運行時執行的代碼中未定義行爲的有效結果。 '-Werror = sequence-point'可能非常有用,但是當使用它時,GCC不再符合C++標準。 'int main(){} void f(int i){++ i ++ ++ i; C是一種嚴格遵守的程序。 (我不確定C++是什麼意思。) – hvd

回答

4

因爲編譯器在一般情況下很難產生硬診斷。你已經展示了一個非常人爲和明顯的例子,但現實通常比這更復雜。只是說「不要這樣做,編譯器也不必爲此告訴你」。

+2

也許一個編譯器無法檢測到的東西的具體例子會是你幫助OP的答案的一個很好的補充。 (類似'++ * p + ++ * q'應該這樣做,當編譯器不知道是否是'p == q'。 – hvd

+0

是否NP-hard或不可判定或確保排序規則被保留? – djechlin

+0

hvd的評論似乎與此答案矛盾。 – djechlin

1

-Werror=sequence-point檢測併發出您正在討論的行爲的編譯錯誤,但在一般情況下會產生誤報。

我不知道寫出符合此標誌的一般實用程序是多麼容易(可能足夠難以使其成爲語言要求)。

我也不知道在什麼意義上,在計算上很難驗證序列點的有效性(不可判定,NP-hard等)。這似乎會影響前一個問題。

+0

正如我所評論的問題,導致有效的程序被拒絕。 – hvd

+0

@hvd你明確知道這個問題比其他人在這個問題上,你能發表一個答案嗎? – djechlin

+0

我最初認爲,但是覺得我不會在@PreferenceBean的答案中添加太多內容。我會再試一次,看看我能不能拿出一些東西。 – hvd

2

在一般情況下,很難檢測任意表達式是否違反排序規則。

int f(int *pa, int *pb) { 
    return ++*pa + ++*pb; 
} 

根據輸入值,它可以具有除了排序以外的其他原因UB, f(0, 0),但是當僅考慮測序時,它是否定義了行爲?

沒有足夠的信息來回答這個問題。它僅在pa == pb的情況下違反了排序規則。沒有什麼可以解決這個問題,但同樣,沒有什麼可以暗示任何代碼都會這樣稱呼它。

如果我們不能說,編譯器不能告訴。因此,它不可能是不合格的,只是未定義的,並且任何診斷都作爲實現問題的質量留下。

事實上,它在運行時未定義,而不是格式不正確,然後會產生另一個結果:這意味着如果代碼被執行,這只是一個問題。我在評論舉了一個例子:

int main() { } 
void f(int i) { ++i + ++i; } 

功能f已不確定的行爲,但該計劃作爲一個整體不會,因爲函數f永遠不會被調用。由於C++標準中不存在或不可能有任何規則禁止這樣做,因此即使對於簡單情況,編譯器也不允許發出錯誤消息。

但是,編譯器總是被允許爲任何代碼發出警告(或任何其他非致命的診斷),所以有用的編譯器會嘗試檢測這個並讓你知道你做錯了什麼。

+0

是的,這個。 :) –