C語言程式設計筆記丨為什麼f(i = -1, i = -1)是未定義行為?
最近在讀order of evaluation violations ,其中的一個例子使我很困惑。
1)如果對一個標量物件的副作用相對於對這個標量物件的另一個副作用是無序的,那麼這是未定義行為。
//程式碼片段 f(i=-1,i=-1);//undefined behavior 未定義行為
在這段程式碼中,很明顯 i 是一個標量物件。
算術型別(3.9.1),列舉型別,指標型別,指標成員型別(3.9.2),空指標型別和被const或volatile修飾的型別(3.9.3)等統稱為標量型別。
從這句話中我看不出上面那句程式碼有什麼分歧的地方。我認為不論第一個引數還是第二個引數先執行,i最終都是-1,並且兩個引數的值都是-1。
有人能解釋清楚這些嗎?
最佳答案:
既然運算是無序的,也就不能說分配任務的指令不能交錯執行。也許會選擇最佳的方式去執行,由CPU的架構來決定。引用下面這句話來說明:
如果A在B之前是無序的並且B在A之前是無序的,那麼存在兩種可能性:
(1)預估A和B是無序的:它們可能以任意的順序執行並且可能會重疊(在一個執行緒的執行中,編譯器可能會交錯組織包含A和B的CPU指令)。
(2)預估A和B是無法確定的順序:它們可能以任意順序執行但是一定不會重疊。或者A在B執行之前完成或者B在A執行之前完成。下一次執行同樣的語句時,執行的順序有可能是相反的。
假設運算執行後,把-1存進一個記憶體地址,就這個行為自身而言,這似乎並不會引發任何問題。但是如果一個指令和另一個指令交錯執行操作同一個記憶體地址,你不能說編譯器不會把這些指令優化成一個獨立的具有同樣效果的指令集,這樣就會出錯了。
例如,假想把記憶體清零然後再遞減是最高效的。現在開始值是-1,然後就是:
f(i=-1,i=-1)
也許會變成:
clear i //清空 i clear i //清空 i decr i //遞減 i decr i //遞減 i
現在i是-2。
這也許是一個假的例子,但可能是真的。