在C中调用函数时的序列点和未定义/未指定的行为

Stu*_*etz 4 c undefined-behavior sequence-points language-lawyer unspecified-behavior

我试图确定我对C中序列点的理解 - 只是想检查一下.目前,我认为(1)是未定义的,而(2)仅仅是未指定的,因为在(2)中,在评估参数gh(因此我们不在i序列点之间修改两次)之后存在序列点,但是参数的评估顺序f仍未指定.我的理解是否正确?

#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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:

这里的关键点似乎是编译器是否可以自由地在任何一个g或者h被调用之前执行增量- 我从下面的答案中理解它是,尽管我很欣赏确认情况就是这样.

Ada*_*eld 12

不正确.序列点指定允许的操作顺序的部分顺序.在情况(2)中,有序列点:

  1. 在行尾的分号(1)
  2. 在评估g(即++i)之后但在调用之前g
  3. 在评估h(即++i)之后但在调用之前h
  4. 在评估f(即之后fg已经返回)但在调用之前的参数之后f
  5. 从...返回后 f

因此,从上到下,偏序看起来像这样:

    1
   / \
  /   \
 2     3
  \   /
   \ /
    4
    |
    | 
    5
Run Code Online (Sandbox Code Playgroud)

因为参数的评估顺序是未指定的,所以2和3不是相互排序的.由于i在序列点1和4之间进行了两次修改,因此行为未定义.