在兩個序列點之間多次修改任何物件

int i = 42;
i = i++; /* Assignment changes variable, post-increment as well */
int a = i++ + i--;

像這樣的程式碼經常導致對 i結果價值的猜測。但是,C 標準並未指定結果,而是指定評估此類表示式會產生未定義的行為。在 C2011 之前,該標準根據所謂的序列點形式化了這些規則 :

在前一個和下一個序列點之間,標量物件應通過表示式的計算至多修改其儲存值一次。此外,先前的值應該是隻讀的,以確定要儲存的值。

(C99 標準,第 6.5 節,第 2 段)

該方案被證明有點過於粗糙,導致某些表達方式表現出與 C99 相關的不確定行為,這似乎是不應該做的。C2011 保留了序列點,但基於測序和它稱之為“之前測序” 的關係,在該區域引入了一種更細微的方法 :

如果對標量物件的副作用相對於對同一標量物件的不同副作用或使用相同標量物件的值進行的值計算未進行排序,則行為未定義。如果表示式的子表示式有多個允許的排序,則如果在任何排序中發生這種未測序的副作用,則行為是不確定的。

(C2011 標準,第 6.5 節,第 2 段)

在之前排序關係的完整細節在這裡描述的時間太長,但它們補充了序列點而不是取代它們,因此它們具有定義某些評估行為的效果,這些評估的行為以前是未定義的。特別是,如果在兩次評估之間存在序列點,那麼序列點之前的序列點將在之後的序列點排序

以下示例具有明確定義的行為:

int i = 42;
i = (i++, i+42); /* The comma-operator creates a sequence point */

以下示例具有未定義的行為:

int i = 42;
printf("%d %d\n", i++, i++); /* commas as separator of function arguments are not comma-operators */

與任何形式的未定義行為一樣,觀察違反排序規則的評估表示式的實際行為並不提供資訊,除非是追溯意義。語言標準沒有為期望這樣的觀察預測甚至同一程式的未來行為提供依據。