为什么我的程序从右到左评估参数?

时间:2019-06-12 09:49:30

标签: c function-call order-of-execution

我正在学习C,所以尝试了以下代码,并得到了7,6而不是6,7的输出。为什么?

#include <stdio.h>
int f1(int);
void main()
{
    int b = 5;
    printf("%d,%d", f1(b), f1(b));
}
int f1(int b)
{
    static int n = 5;
    n++;
    return n;
}

2 个答案:

答案 0 :(得分:11)

函数自变量的求值顺序在C中为未指定。(请注意,这里没有未定义的行为;例如,不允许同时对自变量求值。)

通常,对参数的求值是从右到左或从左到右。

根据经验,如果函数具有副作用(如您的情况一样),或者如果两次传递相同的参数(允许您在其中输入某些内容),则不要在函数参数列表中两次调用相同的函数调用站点进行修改(例如,传递指针)。

答案 1 :(得分:0)

https://en.cppreference.com/w/c/language/eval_order

在C11之前,您必须遵守规则(2)

There is a sequence point after evaluation of the first (left) operand and 
before evaluation of the second (right) operand of the following binary 
operators: && (logical AND), || (logical OR), and , (comma).

因为自变量在C11之前被逗号分隔。这不是最佳选择,因为参数在某些平台上从右向左推。因此,C11添加了规则(12),使其未指定。

A function call that is not sequenced before or sequenced after another 
function call is indeterminately sequenced (CPU instructions that 
constitute different function calls cannot be interleaved, even if the 
functions are inlined)

即使C99指定的初始值设定项仍返回规则(2),在该规则中,相对于逗号运算符,较早的(左)初始值设定项在以后的(右)初始化项之前得到解析。也就是说,直到C11添加规则(13)使其未指定为止。

In initialization list expressions, all evaluations are indeterminately 
sequenced

换句话说,在规则(12)和规则(13)之前,规则(2)中的逗号运算符是指定的行为。规则(2)导致无法在某些平台上优化代码的效率低下。如果结构成员或功能参数的数量超过某个阈值,则没有足够的寄存器。也就是说,“套准压力”成为问题。

从历史上看,聚合类型初始值设定项和函数参数回退到逗号运算符。在C11中,他们特别添加了以下定义:这些聚合类型初始值设定项和函数参数中的逗号不是“逗号运算符”,因此规则(12)和规则(13)有意义,而规则(2)不适用。