順序點,也稱作序列點,是電腦程式中一些執行點,在該點處之前的求值的所有的副作用已經發生,在它之後的求值的所有副作用仍未開始。在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]注意,此例不是逗號運算子。
參考文獻
Wikiwand in your browser!
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.