If parenthesis has a higher precedence then why is increment operator solved first?

一个人想着一个人 提交于 2019-11-26 22:20:45

Expressions are evaluated left to right. Parentheses (and precedence) just express grouping, they don't express ordering of evaluation.

So

 11 * (12 + 5)
++a   ++a

equals

187

Quoting from Eric Lippert's Blog:

The evaluation of an arithmetical expression is controlled by three sets of rules: precedence rules, associativity rules, and order rules.

Precedence rules describe how an underparenthesized expression should be parenthesized when the expression mixes different kinds of operators.

Associativity rules describe how an underparenthesized expression should be parenthesized when the expression has a bunch of the same kind of operator.

Order of evaluation rules describe the order in which each operand in an expression is evaluated.

Higher precedence results in grouping of operands with an operator and doesn't mean the evaluation of operands. It is the order of evaluation which decides sequence of evaluation of sub-expressions in an expression.


Update:

As I can see many programmers think that statement

a = ++a * ( ++a + 5);  

will invoke undefined behavior. Yes it will invoke UB if there is no guarantee of evaluation order of operands of an operator.

But this is not true in context of java programming language. It has well defined behavior in java (as well as in C#). The Java Language Specification states that:

15.7. Evaluation Order

The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.

Example 15.7.1-1. Left-Hand Operand Is Evaluated First

In the following program, the * operator has a left-hand operand that contains an assignment to a variable and a right-hand operand that contains a reference to the same variable. The value produced by the reference will reflect the fact that the assignment occurred first.

class Test1 {
    public static void main(String[] args) {
        int i = 2;
        int j = (i=3) * i;
        System.out.println(j);
    }
}

This program produces the output:

9

It is not permitted for evaluation of the * operator to produce 6 instead of 9.

But, still java specification clearly states that not to write such codes:

It is recommended that code not rely crucially on this specification. Code is usually clearer when each expression contains at most one side effect, as its outermost operation, and when code does not depend on exactly which exception arises as a consequence of the left-to-right evaluation of expressions.

From that snippet

int a = 10;
a = ++a * ( ++a + 5);

Sometimes, the most simple solution is to use javap to understand the evaluation order:

 0: bipush 10 // push 10 onto the stack (stack={10})
 2: istore_1  // store 10 into variable 1 (a = 10, stack={})
 3: iinc 1, 1 // increment local variable 1 by 1 (a = 11, stack={})
 6: iload_1   // push integer in local variable 1 onto the stack (a = 11, stack = {11})
 7: iinc 1, 1 // increment local variable 1 by 1 (a = 12, stack={11})
 10: iload_1  // push integer in local variable 1 onto the stack (a = 12, stack = {12, 11})
 11: iconst_5 // load the int value 5 onto the stack (a = 12, stack = {5, 12, 11})
 12: iadd     // add 5 and 12 (a = 12, stack = {17, 11})
 13: imul     // multiply 17 and 11 (a = 12, stack = {})
  1. a is incremented by 1. (line 3) // a = 11
  2. a is incremented by 1. (line 7) // a = 12
  3. add 5 to a (line 12) // a = 17
  4. multiply 11 to 17 (line 13) // a = 187

(10 + 1 + 1 + 5) * 11 = 187

The effect of parentheses is to control which computed values are used as operands for subsequent operations. They control the sequence in which operations are performed only to the extent that an operation cannot be evaluated until after its operands have been. Consider the expressions:

(a()+b()) * (c()+d())
a() + (b()*c()) + d()

The parenthesis need not (and in Java cannot) affect the order in which a(), b(), c(), and d() are called. They may affect whether the multiplication gets performed before or after d() gets called, but only in very rare circumstances (e.g. d() calling a Java Native Interface which alters the numerical rounding mode used in multiplication in a way Java doesn't know about) would code have any way of knowing or caring whether the multiply was performed before or after d().

Otherwise, what's important is that in the first case, one addition operations will act upon a() and b(), and the other upon c() and d(); the multiplication will act upon a()+b() and c()+d(). In the other case, the first multiplication will act upon b() and c(), the first addition upon a() and the aforementioned product, and the second addition upon the first sum and d().

  int a = 10;
  a = ++a * ( ++a + 5);

above kind of expressions are always evaluated in left to right fashion be it C or JAVA

in this case it is solving like this 11*(12+5) which results in 11*17 = 187 // w.r.t java

but if it we solve the same expression w.r.t C-language

then the answer gets changed as the way of evaluation changes

in c first pre-increment/pre-decrement happens ,so if "N" no of times pre inc/dec are there in the expression then inc/dec will happen first "N" no of times

then the same value will be substituted in each ocurrence of the variable in the expression and the expression value is calculated and after that post increment/decrement happens

i.e a gets incremented to 11 then again 12 as there are two incrementation for a in the expression and then the expression is evaluated as

12*(12+5)=12*17=204 //w.r.t C-language

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!