?
This document uses PHP Chinese website manual Release
(包括函數(shù)調(diào)用表達(dá)式中函數(shù)參數(shù)的評(píng)估順序,以及任何表達(dá)式中子表達(dá)式的評(píng)估順序)的任何C運(yùn)算符的操作數(shù)的評(píng)估順序是未指定的(除非在下面指出)。編譯器將以任何順序?qū)λ鼈冞M(jìn)行評(píng)估,并且可以在再次評(píng)估同一個(gè)表達(dá)式時(shí)選擇另一個(gè)順序。
在C中沒有從左到右或從右到左的評(píng)估概念,這不應(yīng)該與操作符的從左到右和從右到左的關(guān)聯(lián)性相混淆:表達(dá)式f1() + f2() + f3()
被解析為(f1() + f2()) + f3()
由于左operator +的從右到關(guān)聯(lián)性,但函數(shù)調(diào)用f3
可以在運(yùn)行時(shí)首先,最后或之間f1()
或f2()
在運(yùn)行時(shí)進(jìn)行評(píng)估。
編譯器對(duì)每個(gè)表達(dá)式或子表達(dá)式執(zhí)行兩種評(píng)估(兩者都是可選的):
值計(jì)算:計(jì)算表達(dá)式返回的值。這可能涉及確定對(duì)象的身份(左值評(píng)估)或讀取先前分配給對(duì)象的值(右值評(píng)估)
副作用:訪問(wèn)(讀取或?qū)懭耄┯梢鬃兊淖笾抵付ǖ膶?duì)象,修改(寫入)對(duì)象,原子同步(自C11起),修改文件,修改浮點(diǎn)環(huán)境(如果支持)或調(diào)用一個(gè)執(zhí)行任何這些操作的函數(shù)。
如果表達(dá)式不產(chǎn)生副作用,并且編譯器可以確定該值未被使用,則表達(dá)式可能不會(huì)被評(píng)估。
“sequenced-before”是同一線程內(nèi)的評(píng)估之間的不對(duì)稱,傳遞,成對(duì)關(guān)系(如果涉及原子類型和內(nèi)存障礙,它可以跨線程延伸)。
如果一個(gè)序列點(diǎn)存在于子表達(dá)式E1和E2之間,那么E1的值計(jì)算和副作用都被排序 - 在 E2的每個(gè)值計(jì)算和副作用之前
如果在評(píng)估B之前對(duì)評(píng)估A進(jìn)行排序,那么在開始評(píng)估B之前評(píng)估A將會(huì)完成。如果A在B之前未被測(cè)序,而B在A之前被測(cè)序,那么在評(píng)估A開始之前B的評(píng)估將完成。如果A不B之前測(cè)序和B不是A之前測(cè)序,然后兩種可能性存在:A,B的評(píng)價(jià)是未測(cè)序:它們可以以任何順序執(zhí)行,并且可以重疊(單個(gè)執(zhí)行線程內(nèi),編譯器可以交織包含A和B)的A和B評(píng)估的CPU指令是不確定地排序的:它們可以以任何順序執(zhí)行但可能不重疊:A在B之前將是完整的,或者B將在A之前完成。在下一次評(píng)估同一個(gè)表達(dá)式時(shí)是相反的。 | (自C11以來(lái)) |
---|
如果在評(píng)估B之前對(duì)評(píng)估A進(jìn)行排序,那么在開始評(píng)估B之前評(píng)估A將會(huì)完成。
如果A在B之前未被測(cè)序,而B在A之前被測(cè)序,那么在評(píng)估A開始之前B的評(píng)估將完成。
如果A在B和B未在A之前排序之前未被測(cè)序,則存在兩種可能性:
A和B的評(píng)估是不確定的:它們可以以任何順序執(zhí)行并且可以重疊(在單個(gè)執(zhí)行線程內(nèi),編譯器可以交織包括A和B的CPU指令)
A和B的評(píng)估是不確定地排序的:它們可以以任何順序執(zhí)行但可能不重疊:A會(huì)在B之前完成,或B在A之前完成。順序可能與下次相同表達(dá)式相反被評(píng)估。
(since C11)
1)評(píng)估所有函數(shù)參數(shù)和函數(shù)指示符后,以及實(shí)際函數(shù)調(diào)用之前,有一個(gè)序列點(diǎn)。
2)在評(píng)估第一個(gè)(左)操作數(shù)之后以及評(píng)估以下二元運(yùn)算符的第二個(gè)(右)操作數(shù)之前,有一個(gè)序列點(diǎn):( &&
邏輯AND),||
(邏輯OR)和,
(逗號(hào))。
3)在評(píng)估第一個(gè)(左)操作數(shù)之后并且在評(píng)估第二個(gè)或第三個(gè)操作數(shù)(以評(píng)估者為準(zhǔn))之前有一個(gè)序列點(diǎn), ?:
4)在完整表達(dá)式(表達(dá)式不是子表達(dá)式:通常是以分號(hào)或if / switch / while / do的控制語(yǔ)句結(jié)束的表達(dá)式)和下一個(gè)完整表達(dá)式之前有一個(gè)序列點(diǎn)。
5)完整聲明的結(jié)尾處有一個(gè)序列點(diǎn)。6)在函數(shù)返回之前有一個(gè)序列點(diǎn)。7)在格式化I / O中的每個(gè)轉(zhuǎn)換說(shuō)明符相關(guān)的動(dòng)作之后有一個(gè)序列點(diǎn)(特別是,對(duì)于scanf將不同的字段寫入同一變量以及用于讀取和修改或修改相同變量的printf變量不止一次使用%n)8)在每次調(diào)用庫(kù)函數(shù)qsort和bsearch所做的比較函數(shù)之前以及之后,以及任何對(duì)比較函數(shù)的調(diào)用和關(guān)聯(lián)對(duì)象的移動(dòng)之間都有序列點(diǎn)由qsort制作 | (自C99以來(lái)) |
---|---|
9)操作數(shù)對(duì)任何操作符的值計(jì)算(但不是副作用)在操作符結(jié)果的值計(jì)算之前(但不包括其副作用)排序。10)直接賦值運(yùn)算符和所有復(fù)合賦值運(yùn)算符的副作用(左變?cè)男薷模┰谧蠛陀覂蓚€(gè)參數(shù)的值計(jì)算(但不是副作用)之后排序。11)后增量和后減算子的值計(jì)算在其副作用之前被排序。12)在另一個(gè)函數(shù)調(diào)用之前或之后未被排序的函數(shù)調(diào)用被不確定地排序(構(gòu)成不同函數(shù)調(diào)用的CPU指令不能交錯(cuò),即使函數(shù)被內(nèi)聯(lián))13)在初始化列表表達(dá)式中, | (自C11以來(lái)) |
1)如果對(duì)標(biāo)量對(duì)象的副作用相對(duì)于同一標(biāo)量對(duì)象上的另一副作用而言是不確定的,則行為是不確定的。
i = ++i + i++; // undefined behaviori = i++ + 1; // undefined behaviorf(++i, ++i); // undefined behaviorf(i = -1, i = -1); // undefined behavior
2)如果標(biāo)量對(duì)象的副作用相對(duì)于使用相同標(biāo)量對(duì)象的值進(jìn)行值計(jì)算而言是未定序的,則行為是未定義的。
f(i, i++); // undefined behaviora[i] = i++; // undefined bevahior
3)只要子表達(dá)式的至少一個(gè)允許排序允許這樣一個(gè)不確定的副作用,上述規(guī)則就適用。