簡體   English   中英

int a = ++i + ++i 是未定義的行為嗎?

[英]Is int a = ++i + ++i undefined behaviour?

考慮以下代碼:

int main(){
  int i = 0;
  int a = ++i + ++i;
}

我找不到任何說明+的操作數未排序的信息。 所以按照標准,二進制+的操作數的順序是不定序的。

[介紹、執行]/15

給定任意兩個評估 A 和 B,如果 A 在 B 之前排序(或者,等效地,B 在 A 之后排序),則 A 的執行應先於 B 的執行。如果 A 沒有在 B 之前排序並且 B 沒有排序在 A 之前,然后 A 和 B 是無序的。 [注意:未排序評估的執行可以重疊。 ——尾注]

當 A 在 B 之前排序或 B 在 A 之前排序時,評估 A 和 B 的排序不確定,但未指定哪個。[注意:不確定排序的評估不能重疊,但可以先執行。 ——尾注]

引用的意思是 A 的評估可以在 B 之前發生,或者 B 的評估可以在 A 之前發生。並且未排序的評估的執行可以重疊,而不確定序列的評估不能重疊,這是不同的。

由於前綴++ ,我們知道i i值計算之前。

然后按照規則:

表達式(或子表達式)的評估通常包括值計算(包括確定 object 的身份以進行左值評估和獲取先前分配給 object 的值以進行純右值評估)和副作用的啟動

If a side effect on a memory location is unsequenced relative to either another side effect on the same memory location or a value computation using the value of any object in the same memory location, and they are not potentially concurrent, the behavior is undefined

因此,無論 A 的評估是在 B 之前還是相反,對於++i + ++i; . 因為不確定順序的評估不能重疊,所以兩個評估之一必須在另一個之前完全執行。 評估包括價值計算和副作用。 因此, i的一個增量在另一個之前被評估。

然而,未排序的求值遵循不同的規則,因此如果二進制+的操作數的求值是未排序的而不是不確定排序的,則混淆將得到解決。 如果我在上面的分析中遺漏了標准中的某些內容,請糾正我。

更新

我找到了以下句子,這似乎表明評估是無序的:

除非另有說明,否則單個運算符的操作數和單個表達式的子表達式的求值是未排序的。

但是,我不知道如何正確理解這句話。 我想出了兩種解釋:

對於算子 A,A 的操作數的求值是無序的; 對於表達式 B,B 的子表達式的計算彼此之間是無序的。

將單個運算符的操作數的求值視為 A。將單個表達式的子表達式的求值視為 B。A 與 B 無序。

哪種解釋是正確的?

標准文本似乎1暗示行為未定義。

  • <a>+<b>中, <a><b> > 的評估是無序的2,3
  • 這兩個部分具有影響相同 memory 位置的副作用

(1) 在我看來,這部分是明確和清晰的,但我不確定是否有其他部分說相反,或者某些更高級別的概念(例如,什么是程序的執行)在邏輯上沒有被破壞,因為的相互矛盾的規則。 鑒於 C++ 的復雜性,我實際上會對沒有出現錯誤感到非常驚訝。

(2) 在重載operator+的情況下,它們將被不確定地排序(因為規則與 function 調用相同,因此不是未定義的行為:N4713 的 8.5.1.2[5] 說“后綴表達式在每個表達式列表中的表達式和任何默認參數。參數的初始化,包括每個相關的值計算和副作用,相對於任何其他參數的順序是不確定的”)但是對於本機int s 這並不適用,並且行為未定義。

(3) 正文說“除非另有說明,對單個運算符的操作數和單個表達式的子表達式的求值是無序的”。 當然,對於一元運算符,這個問題是無關緊要的(沒有要討論的順序),對於三元?:運算符,有特殊的排序規則。 關於“子表達式”的部分是涵蓋像a[++i][++i]這樣的情況,其中a是例如char ** :在這種情況下,兩個相同的子表達式++i是無序的並且有副作用修改相同的 memory 位置和未定義的行為。 我認為該段落實際上比必要的更復雜,因為運算符的操作數也是表達式的子表達式,因此最后一部分就足夠了。

讓我給出一個答案,使問題的答案更清楚。 首先,考慮以下句子

除非另有說明,否則單個運算符的操作數和單個表達式的子表達式的求值是無序的。

句子可以分成兩部分

1. 除非另有說明,對單個運算符的操作數的評估是無序的。
2. 除非另有說明,對單個表達式的子表達式的評估是無序的。

那么,第 1 部分是什么意思?這意味着一個集合X由一個運算符的這些操作數組成,集合X的每個元素彼此之間是無序的,它們是無序的。句子 2 類似於句子 1,它只是使集合X由表達式的這些子表達式組成。

二元運算符+的那些語句在 [expr.additive] 中進行了描述,而這些與該部分中的操作數序列無關,因此,在運算符上執行的規則1因此,正如標准所說,不序列可以重疊,這是什么意思?這意味着“每個評估的部分甚至可以交錯在一起”(@Ben Voigt 在評論中說)。所以,對於++i + ++i ,通常是這樣的:

If a side effect on a memory location is unsequenced relative to either another side effect on the same memory location or a value computation using the value of any object in the same memory location, and they are not potentially concurrent, the behavior is undefined

所以, int a = ++i + ++i是未定義的行為,這個問題的關鍵是理解下面的句子:

除非另有說明,否則單個運算符的操作數和單個表達式的子表達式的求值是無序的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM