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 标准。我再次惊讶地发现很少提到运算符优先级和结合性。

问题
  • 如果我认为函数总是从左到右求值是错误的,那么表中提到函数优先级和关联性的真正含义是什么?
  • 如果不是 ANSI,谁来定义运算符优先级和关联性?如果定义是 ANSI,为什么很少提到运算符优先级和结合性?运算符优先级和结合性是从 ANSI C 标准推断出来的还是在数学中定义的?
  • 最佳答案

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

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

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

    我们还可以看到一个加法表达式的左操作数扩展为另一个加法表达式,这意味着用 x + y + z , x + y是它的一个子表达式。这定义了 结合性 .

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

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

    对于函数调用运算符,从左到右结合意味着 f()() (例如,如果 f 返回一个函数指针,就会发生这种情况)分组如下:(f())() (当然,另一个方向没有任何意义)。

    现在让我们考虑您正在查看的示例:
    f1() + f2() * f3()
    
    *运算符的优先级高于 +运算符,因此表达式分组如下:
    f1() + (f2() * f3())
    

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

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

    然而,一些运算符确实对其操作数的评估强加了顺序。例如,在 x || y , x总是在 y 之前求值.这允许短路,其中 y如果 x 不需要评估已知已经是 true .

    求值的顺序以前是在 C 和 C++ 中使用序列点定义的,并且两者都已更改术语以根据先序关系来定义事物。如需更多信息,请参阅 Undefined Behaviour and Sequence Points .

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

    相关文章:

    c++ - 返回的鼠标坐标不正确

    c++ - 如何用 Armadillo 加载Matlab矩阵?

    c++ - 使用Spirit Parser框架处理转义

    c++ - 二进制搜索树叶子计数问题

    c - 在替换数组中的数据时遇到问题

    mysql - 为什么涉及用户变量的表达式的求值顺序不确定?

    c - 为 C 中的任何信号设置信号处理程序

    c - 为什么在1核VM上运行4线程程序比在4核的相同VM上运行更快?

    c - 无限循环和奇怪的字符,: while (chars = fgetc(map) ! = EOF)

    c - C中运算符的优先级和关联性