为什么我的程序从右到左计算参数?

Why is my program evaluating arguments right-to-left?

我正在学习 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;
}

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

通常参数的计算是从右到左,或从左到右。

根据经验,如果该函数具有 side-effects(就像您的情况一样),则不要在函数参数列表中调用同一个函数两次,或者如果您两次传递相同的参数允许修改调用站点中的某些内容(例如传递指针)。

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) 不适用。