http://hi.baidu.com/ljy2008wl/blog/item/9990b01d37dee448f3de32b0.html
C 語言中,術語副作用(side effect)是指對資料對象或者檔案的修改。例如,以下語句 var = 99;
的副作用是把 var 的值修改成 99。對錶達式求值也可能產生副作用,例如:
se = 100
對這個運算式求值所產生的副作用就是 se 的值被修改成 100。
序列點(sequence point)是指程式運行中的一個特殊的時間點,在該點之前的所有副作用已經結束,並且後續的副作用還沒發生。
C 語句結束標誌——分號;和括弧()是序列點。也就是說,C 語句中由賦值、自增或者自減等引起的副作用在分號之前必須結束,而side effect的發生的先後順序沒有規定,由編譯器決定,這就是unspecified,相對應的為specified(指定)。我們以後會說到一些包含序列點的運算子。任何完整運算式(full expression)運算結束的那個時間點也是序列點。所謂完整運算式,就是說這個運算式不是子運算式。而所謂的子運算式,則是指運算式中的運算式。例如:
f = ++e % 3
這整個運算式就是一個完整運算式。這個運算式中的 ++e、3 和 ++e % 3 都是它的子運算式。
有了序列點的概念,我們下面來分析一下一個很常見的錯誤:
int x = 1, y;
y = x++ + x++;//錯誤
y=(x++)+(x++);//正確
這裡 y = x++ + x++ 是完整運算式,而 x++ 是它的子運算式。這個完整運算式運算結束的那一點是一個序列點,int x = 1, y; 中的 ; 也是一個序列點。也就是說,x++ + x++ 位於兩個序列點之間。標準規定,在兩個序列點之間,一個對象所儲存的值最多隻能被修改一次。
但是我們清楚可以看到,上面這個例子中,x 的值在兩個序列點之間被修改了兩次。這顯然是錯誤的!這段代碼在不同的編譯器上編譯可能會導致 y
的值有所不同。比較常見的結果是 y 的值最後被修改為 2 或者
3。在此,我不打算就這個問題作更深入的分析,各位只要記住這是錯誤的,別這麼用就可以了。有興趣的話,可以看看以下列出的相關資料。
C 語言標準對副作用和序列點的定義如下:
Accessing a volatile object, modifying an object, modifying a file,
or calling a function that does any of those operations are all side
effects, which are changes in the state of the execution environment.
Evaluation of an expression may produce side effects. At certain
specified points in the execution sequence called sequence points, all
side effects of previous evaluations shall be complete and no side
effects of subsequent evaluations shall have taken place.
翻譯如下:
訪問易變對象,修改對象或檔案,或者調用包含這些操作的函數都是副作用,它們都會改變執行環境的狀態。計算運算式也會引起副作用。執行序列中某些特定的點被稱為序列點。在序列點上,該點之前所有運算的副作用都應該結束,並且後繼運算的副作用還沒發生。