首页 > 解决方案 > C中的运算符评估顺序,它们究竟是如何工作的?

问题描述

我对运算符的求值顺序有几个疑问,在第一个示例中,变量 A 和变量 B 都可以先针对该表达式执行

#include <stdio.h>

int main(void)
{
    int A = 5, B = 3;
    int c = a + b;   // Can any of the variables be executed first, 
                     // depending on the compiler ?
    return 0;
}

在这个例子中,如果函数 g 修改变量 A 可能会产生副作用

#include <stdio.h>

int main(void)
{
    int A = 5, B = 3
    int c = f(A) + g(B);
    return 0;
}

比较运算符,例如 > 运算符,它们的操作数没有顺序吗?

#include <stdio.h>

int main(void)
{
    int A = 5, B = 3
    int c = f(A) > g(B);
    return 0;
}

现在再举一个例子,使用运算符 ,

#include <stdio.h>

int main(void)
{
    int A = 5, B = 3
    int c = f(A, B);
    return 0;
}

简而言之,我给出的所有这些示例,评估顺序,是否取决于编译器?

标签: cgccclang

解决方案


在 C17 6.5/3 中可以找到正式的(但非常无用的)定义:

运算符和操作数的分组由语法指示。除非稍后指定,否则子表达式的副作用和值计算是无序的。

这个单一的,蹩脚的句子是运算符优先级和评估顺序的定义。我们可以而且应该回去阅读 C99 6.5/3,以便找到写得更好、以前规范的文本:

除非稍后指定(对于函数调用 ()、&&、||、?: 和逗号运算符),子表达式的求值顺序和副作用发生的顺序均未指定。

不过意思是一样的。关于评估顺序,当前 C 标准的“子表达式的副作用和值计算是未排序的”部分意味着对于具有多个操作数(以及函数参数列表)的大多数运算符,评估顺序是未指定的行为

这确实意味着顺序取决于编译器,可能没有记录,不应该依赖。这甚至意味着允许同一个编译器在同一个程序中根据具体情况更改顺序!因此,给定代码f(a) + f(b); f(a) + f(b);,它甚至可以像f(a) f(b) f(b) f(a)编译器喜欢的那样执行。

唯一具有明确定义的求值顺序的(非一元)运算符是&&||和。?:,


推荐阅读