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