表达式中的括号是否先评估?

时间:2013-07-01 10:59:12

标签: c operator-precedence associativity

在C中,操作数的评估顺序与运算符优先级和关联性无关。

假设我在C中有一个表达式:expr1 * expr2 + (expr3 + expr4) (中间没有序列点)

  

评估此表达式时:

     
      
  1. 将在expr1和expr之前计算子表达式expr3和expr4   expr2因为括号?

  2.   
  3. 或者,括号是否确保括号内的运算符在括号外的运算符之前进行求值?

  4.         

    括号是否确保操作数或运算符的评估顺序?

3 个答案:

答案 0 :(得分:5)

来自2011年语言标准的在线草稿:

6.5表达
...
3运算符和操作数的分组由语法指示。 85)除非另有说明    后来,子表达的副作用和价值计算都没有排序。 86)
85)语法指定运算符在表达式求值中的优先级,该子表达式与本子条款的主要子条款的顺序相同,优先级最高。因此,例如,允许作为二进制+运算符(6.5.6)的操作数的表达式是在 6.5.1至6.5.6。例外情况是强制转换表达式(6.5.4)作为一元运算符的操作数 (6.5.3),以及以下任何一对运算符之间包含的操作数:分组 括号()(6.5.1),下标括号[](6.5.2.1),函数调用括号()(6.5.2.2),以及 条件运算符? :(6.5.15)。 在每个主要子条款中,运算符具有相同的优先级。左或右相关性是 在每个子条款中通过其中讨论的表达式的语法表示。

86)在程序执行期间被多次评估的表达式中,未经过排序和 对其子表达式的不确定顺序评估不需要一致地执行 不同的评估。

清楚如泥,对吗?这意味着,给出一个像

这样的表达式
x = a++ + b++ * (--c / ++d)

每个子表达式a++b++--c++d都可以按任意顺序进行评估;仅仅因为--c++d按parens分组并不意味着它们首先被评估。此外,在评估表达式后,不必立即应用每个++--的副作用。

所有运算符优先保证是--c / ++d结果将乘以b++的结果,a++的结果将被添加到a++ + a++那个价值;它不保证任何表达式评估之前的任何表达式。

密切注意脚注86;如果上面的表达式出现在循环中,则没有理由期望每次循环都会以相同的顺序评估子表达式。实际上,它们很可能是,但编译器明确地给予了动摇的自由。

由于可以自由地评估表达式并以任何顺序应用副作用,因此某些表达式(如{{1}})不会产生一致的结果;标准明确地将其称为未定义行为,这意味着编译器没有义务以任何特定方式处理该情况。它可以忽略这个问题,它可以发出警告,它可以通过错误停止翻译等,但是没有要求它做任何特定的事情。

答案 1 :(得分:2)

  

1.子表达式expr3和expr4是否会在expr1和expr2 becoz之前进行评估?

没有。 C标准未指定expr1expr2expr3expr4的评估顺序。编译器可以按照它喜欢的任何顺序评估这些子表达式,并且可以根据需要将它们与运算符评估交织。

  

2.或者paranthesis确保在paranthesis之外的操作员将比在paranthesis之外的操作员进行评估?

是。括号将覆盖从正常(((expr1 * expr2) + expr3) + expr4)((expr1 * expr2) + (expr3 + expr4))的运算符优先级。这只是确定运算符的相对顺序。

它可以帮助将评估顺序约束显示为树:

              +
      ________|________
      *               +
  ____|____       ____|____
expr1   expr2   expr3   expr4

对此树中节点的评估要求已对其子节点进行了评估。但这是唯一的限制。

评估顺序可以是:expr2expr3expr4+expr1*+ 。 或者可以是:expr4expr3+expr1expr2*+。 或任何符合上述限制的其他排列。

答案 2 :(得分:1)

括号保证在它们内部的内容在依赖于它们的任何内容之前进行评估。没有了。

在您的示例中,(expr3+expr4)会在将+添加到expr1*expr2之前进行评估。这并不意味着它在expr1*expr2之前进行了评估。