考慮下面的C程序:i = post_increment_i()指定,未指定或未定義的行爲?
int i = 0;
int post_increment_i() { return i++; }
int main() {
i = post_increment_i();
return i;
}
關於2011版的C標準(稱爲C11),下面的替代方案中的哪一個真實的:
- C11保證主返回0.
- C11保證主返回0或1.
- 根據C11,此程序的行爲未定義。
從C11標準相關片段:
5.1.2.3程序執行
訪問的易失性對象,修改對象,修改文件或調用一個函數 那這些操作中的任何一個都是副作用,這些副作用是執行環境的狀態變化。一般表達的評估包括值計算和副作用的啓動。用於左值表達式 的值計算包括確定指定對象的身份。
之前排序是由單個線程執行的評估 之間的非對稱,傳遞,成對關係,其在這些評估之間誘導部分順序。 給定任何兩個評估A和B,如果A在B之前被排序,那麼執行A之前應先執行B.(相反,如果A在B之前被排序,則B在A之後排序爲 )如果A在B之前或之後沒有被測序,則A和B是未測序的 。當A在B之前或之後被測序爲 時,評估A和B被不確定地測序,但未指定哪一個。在對錶達式A和B的評估之間存在序列點 意味着在與B相關聯的每個值計算和副作用 之前對與A相關聯的每個值計算和副作用進行排序。(序列的概述分數見附錄C.)
13)未序貫評估的執行可以交錯。不確定排序的評估不能交錯,但可以按任何順序執行。
6.5表達式
表達式是運營商和操作數的序列,可指定一個 值的計算,或者,指定的對象或功能,或產生副作用,或者說 執行它們的組合。操作符 的操作數的值計算在運算符結果的值計算之前進行排序。
如果標量對象上的副作用是相對於任一不同的副作用 相同標量對象或使用相同的標量 對象的值的值的計算上未測序,該行爲是未定義的。如果子表達式的子表達式存在多個允許的排序順序,則如果在任何排序中出現這種不確定的方面效應,則行爲是不確定的。
6.5.2.2函數調用
有功能指定者的評估和實際 爭論之後,但在實際調用之前的順序點。在被調用函數主體執行前後,在調用函數(包括其他函數調用)中未進行任何其他特定排序的每個評估均相對於被調用函數的執行被不確定地排序。
94)換句話說,函數執行不會互相「交錯」。
6.5.2.4後綴增量和減量運算
後綴的結果++運算符是操作數的值。作爲副作用,操作數對象的值 遞增(即,將相應類型的值1添加到它的值爲 )。 [...]在更新操作數存儲值的副作用 之前,對結果的值計算進行排序。關於函數調用的不確定序列 ,postfix ++的操作是單個評估。
6.5.16分配
賦值運算符存儲在由左操作數所指定的對象的值。 [...]更新左操作數的存儲值的副作用是在左和右操作數的值計算之後按順序排列的 。 的操作數的評估是不確定的。
6.8語句和塊
完整表達式是一個不是另一個表達式或一聲明符的一部分的表達。 以下每一項都是完整的表達式:[...]表達式語句中的表達式; [...](可選)表達式返回 聲明。在完整表達式的評估和下一個要評估的完整表達式的評估之間有一個序列點。
三個替代上述對應於以下三種情況下,分別爲:
- 後綴增量操作者的副作用在主分配之前被測序。
- 後綴增量運算符的副作用在main中的賦值之前或之後進行排序,而C11不指定其中的哪一個。 (換句話說,這兩種副作用是不確定的。)
- 這兩種副作用是不確定的。
看來,第一種選擇持有,通過推理的下列鏈:
考慮規則每個評估調用函數(包括 其他函數調用),是不是另有具體在被調用函數主體的執行之前或之後被執行的被執行的被調用函數的執行被不確定地排序。在6.5.2.2中的。假設A:主要賦值運算符的副作用就是這樣的「評估」。假設B:短語「執行被調用函數」包括後綴增量運算符的值計算和後綴增量運算符的副作用。根據這些假設和上述規則,可以得出I)後綴增量運算符的值計算和副作用都在賦值運算符的副作用之前被排序,或者II)值計算和副作用後綴增量運算符的值都是在賦值運算符的副作用後排序的。
考慮規則更新左操作數的存儲值的副作用是 ,在左和右操作數的值計算之後進行排序。這條規則排除了上面的情況。因此情況II成立。 QED
總的來說,這看起來像一個非常強大的論據。此外,它對應於人們會直觀地考慮最可能的選擇。然而,它確實依賴於對術語「評估」和「被調用函數的執行」(假設A和B)的具體解釋以及不完全直接的推理線,所以我想把它放在那裏看看人們是否有理由相信這種解釋是不正確的。請注意,腳註94與該解釋等同,只有當它也適用於主叫方不與被叫方交織的意義上時,這又意味着「交織」意味着以「abab」意義交織,因爲顯然主叫方與交織在較弱的「aba」意義上的被調用者。另外,備選方案2和3在編譯器內聯函數並執行相同類型的優化以激發爲什麼表達式i = i++
具有未定義行爲的情況下似乎是合理的。
pas de probleme。 – wildplasser