4

我试图确定我对 C 中序列点的理解——只是想检查一些东西。目前,我认为 (1) 是未定义的,而 (2) 只是未指定的,基于在 (2) 中,在评估gand的参数后存在序列点h(因此我们不会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;
}

编辑:

似乎这里的关键点是编译器是否可以在调用gh调用之前自由执行这两个增量 - 我从下面的答案中理解是,尽管我很感激确认是这种情况。

4

2 回答 2

12

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

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

所以偏序看起来像这样,从上到下:

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

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

于 2012-06-12T15:38:27.020 回答
2

不,根据 6.5.2.2 10,在实际调用之前,子表达式参数的评估之间没有序列点。

一种看待它的方式是未指定行为是否未定义。++i如果实现在任何调用g或之前对两个子表达式进行排序,h则行为未定义,但如果++i尽可能晚地评估子表达式(分别在调用g和之前h),则行为未指定。但是,由于实现始终可以自由地在任何允许的未指定行为之间进行选择,因此总体结果是未定义的。

于 2012-06-12T15:33:29.063 回答