在以下函数中:
int fun(int *k) {
*k += 4;
return 3 * (*k) - 1;
}
void main() {
int i = 10, j = 10, sum1, sum2;
sum1 = (i / 2) + fun(&i);
sum2 = fun(&j) + (j / 2);
}
求和1等于46,求和2等于48。如果没有优先级规则,函数将如何运行?
如果没有一致的优先级规则,事情会有多大的不同?
优先级规则告诉我们表达式是如何结构化的,而不是如何评估。在sum1 = (i / 2) + fun(&i);
中,规则告诉我们的内容包括:
i / 2
被分组在一起,因为它在括号中;例如,它不能形成(sum1 = i) / 2 + fun(&i);
(i / 2)
和fun(&i)
被分组在一起,因为+
具有比=
更高的优先级,使得sum1 = ((i / 2) + fun(&i);
而不是(sum1 = (i / 2)) + fun(&i);
优先级规则不会告诉我们先计算i / 2
还是fun(&i)
。事实上,C标准中没有任何规则指定首先评估i / 2
还是fun(&i)
。编译器可以选择。
如果首先评估i / 2
,结果将是10 / 2 + 41
,然后是5 + 41
,最后是46
。如果首先评估fun(&i)
,则结果将是14 / 2 + 41
,然后是7 + 41
,最后是48
。您的编译器选择了前者。它本可以选择后者。
如果没有优先级规则,函数将如何运行?
如果没有规则,我们将不知道函数将如何执行。规则告诉我们它将如何执行。
一些评论断言这个程序的行为是未定义的。这是不正确的。这个误解来自C 2018 6.5 2,其中写道:
如果标量对象上的副作用相对于同一标量对象上不同的副作用或使用同一标量的值进行的值计算是未排序的,则行为是未定义的…
在代码中,i / 2
使用i
,而fun(&i)
包含对i
的"副作用"(通过赋值更改其值(。如果这些都是未排序的,那么行为将是未定义的。然而,在对fun
的自变量求值之后和调用它之前,都有一个序列点,在fun
中的每个完整表达式之后都有序列点,包括它的return
语句。因此,对i
的用途及其副作用有一些排序。这种排序不完全由C标准的规则决定,但正如标准所定义的,它是不确定的排序,而不是未排序的。