![](/img/trans.png)
[英]Is the order of evaluation with comma operator & assignment in C predictable?
[英]C order of evaluation of assignment statement
我遇到過跨平台代碼在基本賦值語句中表現不同的情況。
一個編譯器首先評估Lvalue,然后評估Rvalue,然后評估分配。
另一個編譯器首先執行Rvalue,然后執行Lvalue,然后執行賦值。
如果Lvalue影響Rvalue的值,這可能會產生影響,如下例所示:
struct MM {
int m;
}
int helper (struct MM** ppmm ) {
(*ppmm) = (struct MM *) malloc (sizeof (struct MM));
(*ppmm)->m = 1000;
return 100;
}
int main() {
struct MM mm = {500};
struct MM* pmm = &mm
pmm->m = helper(&pmm);
printf(" %d %d " , mm.m , pmm->m);
}
上面的例子,行pmm->m = helper(&mm);
,取決於評估的順序。 如果首先評估左值,則pmm-> m等於mm.m,如果首先計算的Rvalue大於pmm-> m,則等於堆上分配的MM實例。
我的問題是,是否有一個C標准來確定評估的順序(沒有找到任何),或者每個編譯器都可以選擇做什么。 還有其他類似的陷阱我應該知道嗎?
評估=
表達式的語義包括
在左右操作數的值計算之后,對更新左操作數的存儲值的副作用進行排序。 對操作數的評估是不確定的。
(C2011,6.5.16 / 3;重點補充)
強調的規定明確允許您在不同編譯器編譯時觀察到程序行為的差異。 此外, 無序表示,除其他外,即使在程序的同一構建的不同運行中,也允許評估以不同的順序發生。 如果多次調用出現未序列評估的函數,則允許在同一程序執行期間的不同調用期間以不同的順序進行評估。
這已經回答了這個問題,但重要的是要看到更大的圖景。 修改對象或調用執行此操作的函數是副作用(C2011,5.1.2.3 / 2)。 因此,這項關鍵條款發揮作用:
如果相對於對同一標量對象的不同副作用或使用相同標量對象的值進行值計算,對標量對象的副作用未被排序,則行為未定義。
(C2011,6.5 / 2)
被調用的函數具有修改存儲在main()
的變量pmm
的值的副作用,賦值的左側操作數的評估涉及使用pmm
的值進行的值計算,並且這些是未排序的,因此行為是未定義。
不惜一切代價避免未定義的行為。 由於您的程序行為未定義,因此不限於您觀察到的兩種替代方案(如果不夠糟糕)。 C標准對其可能做的事情沒有任何限制。 它可能會崩潰,將您的硬盤驅動器的分區表歸零,或者,如果您有合適的硬件,則召喚鼻子惡魔。 或其他任何東西。 其中大部分都不太可能,但最好的觀點是,如果你的程序有不確定的行為,那么你的程序就錯了 。
使用簡單賦值運算符時: =
,未指定操作數的評估順序。 評估之間也沒有序列點。
例如,如果您有兩個功能:
*Get() = logf(2.0f);
它沒有指定在任何時候調用它們的順序,但是這個行為是完全定義的。
函數調用將引入序列點。 它將在評估參數之后和實際調用之前發生。 經營者;
還將介紹一個序列點。 這很重要,因為在沒有插入序列點的情況下,對象不得修改兩次,否則行為未定義。
由於未指定的行為,您的示例特別復雜,並且可能會有不同的結果,具體取決於首先計算左或右操作數。
計算左操作數,指針pmm
將指向結構mm
。 然后調用該函數,並出現一個序列點。 它通過將指針指向已分配的內存來修改指針pmm
,然后由於操作符而后跟一個序列點;
。 然后它將值1000存儲到成員m
,然后是另一個序列點,因為;
。 該函數返回100並將其分配給左操作數,但由於左操作數首先被計算,值100,它被賦值給對象mm
,更具體地說是它的成員m
。
mm->m
的值為100,而ppm->m
的值為1000.這是定義的行為,在序列點之間沒有對象被修改兩次。
首先調用該函數,發生序列點,它通過將指針指向新分配的結構,然后是序列點來修改指針ppm
。 然后它將值1000存儲到成員m
,然后是序列點。 然后函數返回。 然后評估左操作數, ppm->m
將指向新分配的結構,並通過為其賦值100來修改其成員m
。
mm->m
將具有值500,因為它從未被修改,並且pmm->m
將具有值100.沒有對象在序列點之間被修改兩次。 行為已定義。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.