TAG: C, 序列點
DATE: 2013-08-07
序列點是程序執行序列中一些特殊的點。 當有序列點存在時,序列點前面的表達式必須求值完畢,並且副作用也已經發生, 才會計算序列點后面的表達式和其副作用。
什么是副作用?舉例子來說明。
int a = 5;
int b = a ++;
在給b賦值的語句中,表達式a++
就有副作用,它返回a
當前的值5后,要對a
進行加1的操作。
哪些符號會生成序列點呢?
",
"會生成序列點。
",
"用於把多條語句拼接成一條語句。 例如:
int b = 5;
++ b;
可由",
"拼接成
int b = 5, ++b;
因為",
"會產生序列點,所以",
"左邊的表達式必須先求值,如果有副作用,副作用也會生效。然后才會繼續處理",
"右邊的表達式。
&&
和||
會產生序列點
邏輯與 &&
和邏輯或 ||
會產生序列點。
因為&&
支持短路操作,必須先將&&
左邊的表達式計算完畢,如果結果為false
,則不必再計算&&
右邊的表達式,直接返回false
。
||
和&&
類似。
?:
中的"?
"會產生序列點
三元操作符 ?:
中的"?
"會產生序列點。 如:
int a = 5;
int b = a++ > 5? 0 : a;
b
的結果是什么?因為"?
"處有序列點,其左邊的表達式必須先求值完畢。 a++ > 5
在和5比較時,a
並沒有自增,所以表達式求值為false
。 因為"?
"處的序列點,其左邊表達式的副作用也要立即生效,即a
自增1,變為6。 因為"?
"左邊的表達式求值為false
,所以三元操作符?:
返回:
右邊的值a
。 此時a
的值是6,所以b
的值是6。
序列點之間的執行順序
奇怪的C代碼中給出的例子。
int i = 3;
int ans = (++i)+(++i)+(++i);
(++i)+(++i)+(++i)
之間並沒有序列點,它們的執行順序如何呢? gcc編譯后,先執行兩個++i
,把它們相加后,再計算第三個++i
, 再相加。而Microsoft VC++編譯后,先執行三個++i
,再相加。 兩者得到的結果不同,誰對誰錯呢?
誰也沒有錯。C標准規定:兩個序列點之間的執行順序是任意的。 當然這個任意是在不違背操作符優先級和結合特性的前提下的。 這個規定的意義是為編譯器的優化留下空間。
知道這個規定,我們就應該避免在一行代碼中重復出現被遞增的同一個變量, 因為編譯器的行為不可預測。 試想如果(++i)+(++i)+(++i)
換成(++a)+(++b)+(++c)
(其中a
、b
、c
是不同的變量), 不管++a
,++b
和++c
的求值順序誰先誰后,結果都會是一致的。