函数调用的序列点?
这是另一个序列点问题,但是一个相当简单的问题:
#include void f(int p, int) { printf("p: %d\n", p); } int g(int* p) { *p = 42; return 0; } int main() { int p = 0; f(p, g(&p)); return 0; }
这是未定义的行为吗? 或者对g(&p)
的调用是否作为序列点?
不。它不会调用未定义的行为。 它只是未指定 ,因为在标准中未指定评估函数参数的顺序。 因此输出可以是0
或42
具体取决于编译器决定的评估顺序。
程序的行为未指定,因为我们不知道函数参数的评估顺序,从草案C ++标准 1.9
程序执行段落3 :
抽象机器的某些其他方面和操作在本国际标准中描述为未指定的(例如,对函数的参数的评估顺序)。 在可能的情况下,本国际标准定义了一组允许的行为。 […]
在输入函数之前,参数的所有副作用都按照第5.2.2
节函数调用第8节的顺序排序:
[注意:后缀表达式和参数表达式的评估都是相对于彼此的未经测序的。 在输入函数之前,对参数表达式评估的所有副作用进行排序 (参见1.9)。 – 尾注]
至于C
,第6.5.2.2
节函数调用第10段中的C99标准草案都涵盖了这两点:
函数指示符的评估顺序,实际参数和实际参数中的子表达式是未指定的,但在实际调用之前有一个序列点。
因此,在C
和C++
中,最终可以得到f(0,0)
或f(42,0)
。