轉貼自﹝工程師的家

code:
i=0; i=i++;

這樣的程式,最後 i 的值會是多少?0 還是 1 或其它值?
我在網路上看過幾個類似的問題,回覆的答案也是莫衷一是。
對大部份的 C/C++ Compiler測試的結果是 1,
有人把它拿到 java 上測試,發現結果是 0 。
但 C/C++ 和 java 對這樣表示式的計算規則是一樣的啊!
是java不好?還是 C/C++ 錯了?事實上,都不是,
是程式寫得有問題!

ANSI C/C++ 運算式(expression)有一個但書:
如果一個左值(l-value)在運算式中被改變了兩次以上,除非運算子
能保證其計算次序,否則運算式的結果是未定義的

很明顯的 i 在運算式中被改變了兩次,所以:
運算後 i 的結果在ANSI C/C++的規格是未定義的,它依compiler 所用的運
算式演算法不同而有不同的結果,用你手上的C++ Compiler,i的結果可能
是0或是1甚至是其它的值,但不表示其它家的C++compiler 會有一樣的結
果; 甚至你手上C++的下一個版本都不保證會和現在一樣。因為它們都未違
反ANSI 的法律!

很多程式員並不熟讀程式語言的細節而容易犯下這樣的錯,原來跑得好好的
程式在compiler換上新版本後出現了問題。通常直覺的會去怪"新版本"的
compiler有bug!但十有八九問題是出在自己的程式。

”一個左值(l-value)在運算式中被改變了兩次以上,除非運算子 能保證
其計算次序,否則運算式的結果是未定義的”
這在C/C++原始的定義是這樣的:
一個運算式中若含有子運算式,子運算式的計值次序是未定義。
(未定義的意思是ANSI 未規範,編譯器可自行依演算法之差異而便宜行事)
i=i++; 這個運算式來說它分成
i=i;//<—主運算式
i=i+1;//<—子運算式

兩個運算式
因為子運算式(i=i+1)計值次序未定義,所以主運算式的右值 i 到底是新值或
舊值便無法確定,所以最後指派到i的值便未定義。
那麼什麼運算子可以保證子運算式的計值次序?就是”循序”運算子:逗號 (,)
像這樣的式子是正確的運算式:
j=i++, i=j+2;
循序運算子保證其左邊會先於右邊計值。

注意到在C/C++裡只有運算式中的逗號是循序運算子,不是所有的逗號都
是循序運算子。
例如呼叫函式:
FuncCall(i, j*i++);
這程的函式的呼叫是錯的,兩個引數中間的逗號是”分隔符號”不是”循序
運算子”。C/C++也不保證引數的計值次序,結果是第一個引數值是不確定的。

發表迴響

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料