4

我試圖讓我對C中序列點的理解 - 只是想檢查一下。目前,我認爲(1)是不確定的,而(2)僅僅是沒有說明的,因爲在(2)中,在評估參數gh(因此我們不修改i兩次序列點),但f參數的評估順序仍未明確。我的理解是否正確?以C調用函數時的序列點以及未定義/未指定的行爲

#include <stdio.h> 

int g(int i) { 
    return i; 
} 

int h(int i) { 
    return i; 
} 

void f(int x, int y) { 
    printf("%i", x + y); 
} 

int main() { 
    int i = 23; 
    f(++i, ++i); // (1) 
    f(g(++i), h(++i)); // (2) 
    return 0; 
} 

編輯:

看來關鍵的一點是這裏的編譯器是否可以自由地執行這兩個無論是gh之前的增量被稱爲 - 我從下面的答案的理解是,它是,雖然我很欣賞確認情況。

+0

恩,不要那樣做! :) –

+2

@MichaelDorgan:我不會:)我正在研究一個靜態分析工具來幫助阻止人們做這樣的事情,這個區別可能很重要。 –

回答

2

不,根據6.5.2.2 10,在實際調用之前評估子表達式參數之間沒有序列點。

查看它的一種方式是未指定是否行爲未定義;如果在任何調用gh之前執行序列的兩個子表達式,那麼行爲是不確定的,但是如果++i子表達式評估的時間越晚(分別在調用gh之前立即),則行爲是未指定的。但是,由於實現始終可以自由選擇任何允許的未指定行爲,因此總體結果是未定義的。

+0

沒錯 - 所以在'g'和'h'被調用之前,兩個'++ i's都可能發生,在這種情況下,沒有順序點,並且它是未定義的。 –

+5

*未指定行爲是否未定義*:我認爲C中沒有這樣的事情。這裏的行爲未定義。 – ouah

+0

我認爲,儘管術語,我會給這個答案,因爲它實際上幫助我更多的思考(我提出了兩個答案,雖然他們都有幫助)。如果我猜想術語可能會被收緊的話,對未來的讀者可能會有所幫助。 –

12

不正確。序列點指定部分訂單關於允許的操作順序。在情況(2)中,有序列點:

  1. 在在該行的末尾的分號(1)
  2. g參數的評估之後(即++i),但在調用之前g
  3. h參數(即++i),但調用h
  4. f參數的評估後前(即fg後已經返回)的評估之後,但befo重新調用f
  5. f

所以部分順序是這樣的,從上到下回歸後:

1 
/\ 
/ \ 
2  3 
    \ /
    \/
    4 
    | 
    | 
    5 

2和3未相對於責令對方因爲參數評估的順序是未指定的。由於i在序列點1和4之間被修改兩次,因此行爲未定義。

+0

啊對,很高興我檢查了!我意識到序列點是偏序的事實,但我的想法如下 - 由於論證評估的順序未指定,因此您可以選擇1 - > 2 - > 3 - > 4 - > 5或1 - > 3 - > 2 - > 4 - > 5.在任何一種情況下,我都認爲在1和4之間有一個序列點(在2或3處)。似乎我完全錯過了這一點。 –

+1

我並不反對這種方法,但我認爲它不會立即遵循標準; 6.5 2表示一個對象最多可以在*相鄰*序列點之間修改一次,但是1和4在上面的圖中是不相鄰的。如果序列點圖是線性化的,那麼執行所需的行爲如何? – ecatmur

+0

@ecatmur:恩,好點。我查看了標準,我也無法弄清楚。 C99§6.5/ 2表示「在前一個和下一個序列點之間......」,但不清楚#1之後的「下一個序列點」是什麼 - g'和'h'的評估順序未指定,並且在評估它們的參數之後但在調用它們之前它們各自具有序列點,並且這兩個序列點出現在#4之前。 –

相關問題