这是另一个序列点问题,但相当简单:
#include <stdio.h>
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)
充当序列点?
这是另一个序列点问题,但相当简单:
#include <stdio.h>
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)
充当序列点?
不,它不会调用未定义的行为。它只是unspecified,因为标准中未指定评估函数参数的顺序。因此输出可能是0
或42
取决于编译器决定的评估顺序。
程序的行为是未指定的,因为我们不知道函数参数的评估顺序,来自草案 C++ 标准 1.9
程序执行第 3 段:
抽象机的某些其他方面和操作在本国际标准中描述为未指定(例如,函数参数的评估顺序)。在可能的情况下,本国际标准定义了一组允许的行为。[...]
并且参数的所有副作用都在输入函数之前排序,来自5.2.2
函数调用第 8 段:
[注意:后缀表达式和参数表达式的计算相对于彼此都是无序的。参数表达式求值的所有副作用都在输入函数之前排序(见 1.9)。——尾注]
至于这两点, C99 草案标准中的功能调用第 10 段C
中涵盖了这两个点:6.5.2.2
函数指示符、实际参数和实际参数中的子表达式的求值顺序未指定,但在实际调用之前有一个顺序点。
因此,在两者中C
,C++
您都可以以f(0,0)
or结束f(42,0)
。