2011-05-19 71 views
21

相關問題:Any good reason why assignment operator isn't a sequence point?是i = f();當f修改我時定義?

comp.lang.c FAQ我會推斷下面的程序是未定義的。奇怪的是,它只提到f作爲一個序列點,在參數的計算和控制轉移到f之間。從f回到調用表達式的控制轉移不會列爲序列點。

int f(void) { i++; return 42; } 
i = f(); 

它真的沒有定義?

作爲一個結束語,我補充了很多我的問題,我對靜態分析的上下文感興趣。我不是自己寫這個,我只是想知道我是否應該在其他人編寫的程序中提出警告。

+19

對於任何可能引起關注的人來說,「你總是可以試用它」對於「X是一個未定義的行爲?」從來都不是正確的答案。 – 2011-05-19 07:35:58

+0

+1,但也要注意UB不一定是壞的。 C不禁止使用UB,它只是說「我不知道會發生什麼,希望你能做到。」 – Philip 2011-05-19 11:33:07

+5

UB不好。與實現定義的行爲不同,編譯器作者的預期用法是,即使在同一編譯器的不同版本之間,行爲也可能會發生變化,並根據有效代碼的最佳服務優化進行更改。 – 2011-05-19 11:40:52

回答

9

控制的選自F回 轉印主叫表達未列出 作爲序列點。

是的。

評價的端部的充分表達

 

形成一個 表達式語句中的完整的表達,或一個在 控制表達式之一if, switch,while,for,or do/while statement,or the expression in an 初始化程序或返回語句

你有一個return語句,因此,你有一個序列點。

,它甚至沒有出現的

int f(void) { return i++; } // sequence point here, so I guess we're good 
i = f(); 

是不確定的。 (對我來說有點奇怪)

+2

那麼,如果編譯器試圖嵌入它,會發生什麼?編輯:一切都打破了,很高興知道... – 2011-05-19 07:49:23

+0

哦,我明白了爲什麼,(返回i ++)按照預期對i進行評估,然後遞增i,結束序列點。然後將舊i分配給i,序列點結束。 – 2011-05-19 07:55:42

+10

@詹姆斯格林哈爾格:沒有什麼突破。關於序列點內容的改變絕對沒有。 「序列點」是一個概念,而不是某種與身體功能體相關的物理實體。代碼無論如何都是可以的,因爲每個函數在入口處和結尾都有一個序列點,而不管它是否被內聯。 – AnT 2011-05-19 08:13:22

8

這根本沒有定義。 C99附錄C中列出的序列點之一是完整表達式的結尾,其中一個是return語句中的表達式。

由於您要返回42,因此在return語句後面緊跟着一個序列點。

爲了完整起見,C99序列點這裏列出,有關一個粗體:

以下5.1.2.3中所描述的序列點:


  • 電話到函數,在參數被評估後(6.5.2.2)。
  • 以下運算符的第一個操作數的結尾:邏輯AND & &(6.5.13);邏輯OR || (6.5.14);有條件? (6.5.15);逗號(6.5.17)。
  • 完整聲明的結束:聲明符(6.7.5);
  • 完整表達式的結尾:初始值設定項(6.7.8);表達式語句(6.8.3)中的表達式;選擇語句的控制表達式(if或switch)(6.8.4);一個while或do語句的控制表達式(6.8.5); for語句的每個表達式(6.8.5.3); 返回語句(6.8.6.4)中的表達式。
  • 緊接庫函數返回之前(7.1.4)。
  • 在與每個格式化輸入/輸出功能轉換 說明符(7.19.6,7.24.2)相關聯的操作之後。
  • 緊接在每次調用比較函數之前和緊接之後,以及 也在任何調用比較函數和任何移動的對象 作爲參數傳遞給該調用(7.20.5)之間。
+0

你確定你的例子是沒有函數的UB嗎?我認爲這是完全明確的。該對象只被訪問(讀取)一次,它用於確定要分配給它的新值。我沒有看到任何會引用UB的東西。 – 2011-05-19 11:44:26

+0

啊,我看到它是從標準的,但我仍然無法找到任何理由,爲什麼它會是UB ...... – 2011-05-19 11:47:14

+1

@ R。是因爲g是工會嗎? g.u2.f3 = g.u1.f2當然看起來會調用undefined behvaiour。 – 2011-05-19 13:47:55