順序點
順序點,也稱作序列點,是計算機程序中一些執行點,在該點處之前的求值的所有的副作用已經發生,在它之後的求值的所有副作用仍未開始。在C與C++程序設計語言中,表達式的值依賴於它的子表達式的求值順序。增加更多的順序點限制了可能的求值順序,能保證有一個一致結果。
C++11中,順序點概念已經被sequenced before這種方法取代:直接指出一個求值是在另一個求值之前,或者兩個求值是無順序的。[1][2]無順序的求值可以重疊進行。
歧義例子
考慮兩個函數f()
與g()
。在C與C++中,加法運算符+
不是一個順序點,因此表達式f() + g()
可能會先調用f()
,或先調用g()
。逗號運算符引入了一個順序點,因此表達式f(), g()
的求值順序是確定的:首先調用f()
,然後調用g()
。
當一個變量在一個表達式修改不止一次,順序點也發揮作用。一個典型的C語言例子是表達式i = i++
,其中i
的結果值是有二義性的,依賴於表達式求值順序:自增運算可能發生在賦值之前、之後或者交錯進行。在C與C++語言中,這會導致未定義行為。[3]
C與C++的順序點
在C[4]與C++[5]中,順序點出現在下述位置:(C++的重載操作符的行為類似於函數)
&&
(邏輯與)、||
(邏輯或)、逗號運算符的左操作數與右操作數求值之間(前兩者是短路求值的一部分)。例如,表達式*p++ != 0 && *q++ != 0
,子表達式*p++ != 0
的副作用都會在試圖訪問q
之前完成。- 三元條件運算符的第一個操作數之後,第二或第三操作數之前。例如,表達式
a = (*p++) ? (*p++) : 0
在第一個*p++
之後存在順序點,因而在第二個*p++
求值之前已經做完一次自增。 - 完整表達式結束處。包括表達式語句(如賦值
a = b;
),返回語句,if
、switch
、while
、do
-while
語句的控制表達式,for
語句的3個表達式。 - 函數調用時的函數入口點。函數實參的求值順序未指定,但順序點意味着這些實參求值的副作用在進入函數時都已經完成。表達式
f(i++) + g(j++) + h(k++)
,調用f()
,g()
,h()
的順序未指定,i
,j
,k
的自增順序也未指定。函數調用f(a,b,c)
的實參列表不是逗號運算符,a
,b
,c
的求值順序未指定。 - 函數返回時,在返回值已經複製到調用上下文。(僅C++標準指出這一順序點[6])
- 初始化的結束。例如,聲明
int a = 5;
中的對5
求值之後。 - 初始化列表的以逗號分割的各個初始化值,嚴格遵照從左至右求值。例如:
int a[3] = {i++,j--,foo(101)};
注意,此處不是逗號運算符。(從C++11標準指出這一順序點) - 在聲明序列的每個聲明(declarator)之間。例如,
int x = a++, y = a++
的兩次a++
求值之間。[7]注意,此例不是逗號運算符。
參考文獻
- ^ ISO/IEC 14882:2011. [2012-07-04]. (原始內容存檔於2013-05-17).
- ^ A finer-grained alternative to sequence points (revised) (WG21/N2239 J16/07-0099). [2012-07-05]. (原始內容存檔於2021-03-07).
- ^ Clause 6.5#2 of the C99 specification: "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored."
- ^ C99 規範的附錄 C 中列出了可以假定序列點位置的情況。
- ^ The 1998 C++ standard lists sequence points for that language in section 1.9, paragraphs 16–18.
- ^ C++ standard, ISO 14882:2003, section 1.9, footnote 11.
- ^ C++ standard, ISO 14882:2003, section 8.3: "Each init-declarator in a declaration is analyzed separately as if it was in a declaration by itself."
- Question 3.8 (頁面存檔備份,存於網際網路檔案館) of the FAQ for comp.lang.c