c++ - 谁定义了 C 运算符优先级和关联性?

标签 c++ c operator-precedence associativity ansi-c

简介

在每本有关 C/C++ 的教科书中,您都会找到如下所示的运算符优先级和关联性表:

Operator Precedence And Associativity Table

http://en.cppreference.com/w/cpp/language/operator_precedence

StackOverflow 上的一个问题是这样问的:

以下函数按什么顺序执行:

f1() * f2() + f3();
f1() + f2() * f3();

引用上一张图表,我自信地回答说函数具有从左到右的关联性,因此在前面的陈述中,在这两种情况下都是这样评估的:

f1() -> f2() -> f3()

函数评估完成后,您可以像这样完成评估:

(a1 * a2) + a3
a1 + (a2 * a3)

令我惊讶的是,很多人告诉我我完全错了。决心证明他们错了,我决定转向 ANSI C11 标准。我再次惊讶地发现,很少有人提到运算符优先级和关联性。

问题

  1. 如果我认为函数总是从左到右求值的观点是错误的,那么表中提到函数优先级和关联性的真正含义是什么?
  2. 如果不是 ANSI,谁来定义运算符优先级和关联性?如果是ANSI做出定义,为什么很少提及运算符优先级和关联性?运算符优先级和关联性是从 ANSI C 标准推断出来的,还是在数学中定义的?

最佳答案

运算符优先级在适当的标准中定义。 C 和 C++ 的标准是 C 和 C++ 到底是什么的一个真正定义。所以如果你仔细观察,细节就在那里。事实上,细节在语言的语法中。例如,看一下 C++ 中 +- 的语法产生规则(统称为 additive-expressions):

additive-expression:
  multiplicative-expression
  additive-expression + multiplicative-expression
  additive-expression - multiplicative-expression

如您所见,乘法表达式加法表达式的子规则。这意味着如果你有类似 x + y * z 的东西,y * z 表达式是 x + y * z 的子表达式。这定义了这两个运算符之间的优先级

我们还可以看到 additive-expression 的左操作数扩展为另一个 additive-expression,这意味着 x + y + z, x + y 是它的子表达式。这定义了关联性

关联性决定了如何对同一运算符的相邻使用进行分组。例如,+ 是从左到右关联的,这意味着 x + y + z 将像这样分组:(x + y) + z .

不要将其误认为是评估顺序。绝对没有理由不能在 x + y 之前计算出 z 的值。重要的是计算的是 x + y 而不是 y + z

对于函数调用运算符,从左到右的关联性意味着 f()()(例如,如果 f 返回函数指针,则可能发生这种情况)像这样分组:(f())()(当然,另一个方向没有任何意义)。

现在让我们考虑一下您正在查看的示例:

f1() + f2() * f3()

* 运算符的优先级高于 + 运算符,因此表达式按如下方式分组:

f1() + (f2() * f3())

我们甚至不必在这里考虑关联性,因为我们没有任何相同的运算符彼此相邻。

然而,函数调用表达式的求值是完全无序的。没有理由不能先调用 f3,然后调用 f1,然后调用 f2。在这种情况下,唯一的要求是运算符的操作数在运算符之前进行评估。所以这意味着必须在评估 * 之前调用 f2f3 并且必须评估 *并且必须在评估 + 之前调用 f1

但是,有些运算符确实会对其操作数的求值进行排序。例如,在 x || yx 总是在 y 之前计算。这允许短路,如果 x 已知为 true,则不需要评估 y

之前在 C 和 C++ 中使用 sequence points 定义了求值顺序,并且两者都更改了术语以根据 sequenced before 关系来定义事物.如需更多信息,请参阅 Undefined Behaviour and Sequence Points .

关于c++ - 谁定义了 C 运算符优先级和关联性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20767745/

相关文章:

c++ - VC++ 2013 调试和发布版本

c - 时间片是如何在进程中的 pthreads 之间划分的?

c - TCP:客户端连接,发送数据并在接受之前断开连接时会发生什么

c++ - 与 ? 一起使用时的逗号运算符优先级: operator

c++ - 使用 sleep() 时生产者消费者(使用 Monitor)代码不工作?

c++ - 复数和朴素傅立叶变换 (C++)

c - 未定义行为或非未定义行为

c - C中的短路和运算符优先级

perl - Perl 中的逗号在所有上下文中都是关联的吗?

c++ - C++中std::multiset::count的时间复杂度是多少?