Does the order of operations change within an if expression?

放肆的年华 提交于 2020-01-31 04:08:25

问题


I recently came across something that I thought I understood right off the bat, but thinking more on it I would like understanding on why it works the way it does.

Consider the code below. The (x-- == 9) is clearly getting evaluated, while the (y++ == 11) is not. My first thought was that logical && kicks in, sees that the expression has already become false, and kicks out before evaluating the second part of the expression.

The more I think about it, the more I don't understand why this behaves as it does. As I understand it, logical operators fall below increment operations in the order of precedence. Shouldn't (y++ == 11) be evaluated, even though the overall expression has already become false?

In other words, shouldn't the order of operations dictate that (y++ == 11) be evaluated before the if statement realizes the expression as a whole will be false?

#include <iostream>
using namespace std;

int main( int argc, char** argv )
{
    int x = 10;
    int y = 10;

    if( (x-- == 9) && (y++ == 11) )
    {
        cout << "I better not get here!" << endl;
    }

    cout << "Final X: " << x << endl;
    cout << "Final Y: " << y << endl;
    return 0;
}

Output:

Final X: 9
Final Y: 10

回答1:


logical operators fall below increment operations in the order of precedence.

Order of precedence is not order of execution. They're completely different concepts. Order of precedence only affects order of execution to the extent that operands are evaluated before their operator, and order of precedence helps tell you what the operands are of each operator.

Short-circuiting operators are a partial exception even to the rule that operands are evaluated before the operator, since they evaluate the LHS, then the operator has its say whether or not to evaluate the RHS, maybe the RHS is evaluated, then the result of the operator is computed.

Do not think of higher-precedence operations "executing first". Think of them "binding tighter". ++ has higher precedence than &&, and in the expression x ++ && y ++, operator precedence means that the ++ "binds more tightly" to y than && does, and so the expression overall is equivalent to (x++) && (y++), not (x++ && y) ++.




回答2:


Shouldn't (y++ == 11) be evaluated, even though the overall expression has already become false?

No: the && and || operators short-circuit: they are evaluated left-to-right and as soon as the result of the expression is known, evaluation stops (that is, as soon as the expression is known to be false in the case of a series of &&, or true in the case of a series of ||)(*).

There is no sense in doing extra work that doesn't need to be done. This short-circuiting behavior is also quite useful and enables the writing of terser code. For example, given a pointer to a struct-type object, you can test whether the pointer is null and then dereference the pointer in a subsequent subexpression, for example: if (p && p->is_set) { /* ... */ }.


(*) Note that in C++, you can overload both the && and the || for class-type operands and if you do, they lose their short-circuiting property (it is generally inadvisable to overload && and || for this reason).




回答3:


Precedence and associativity do not specify the order in which the operations are actually performed. They specify how operations are grouped: that is, in the following expression:

x && y++

...the lower precedence of && says that it is grouped as if it was:

x && (y++)

rather than as

(x && y)++

In your expression, the relative precedence of && and ++ do not matter, because you have separated those operators with parentheses anyway.

Grouping (and therefore precedence and associativity) specify what value each operator is operating on; but it specifies nothing about when it does so.

For most operators, the order in which the operations are performed is unspecified - however, in the case of && it is specified to evaluate the left hand operand first, then only evaluate the right hand operand if the result of the left hand operand was non-zero.




回答4:


No. Order of precedence simply decides whether you get this:

A && B

(with A being x-- == 9 and B being y++ == 11) or

A == B == C

(with A being x--, B being 9 && y++, and C being 11).

Obviously, we're dealing with the first case. Short circuiting fully applies; if A is true, then B is not evaluated.




回答5:


The conditional operators evaluate left-to-right and stop as soon as the result is known (an AND with a falsity or an OR with a true value).




回答6:


C standard does not dictate any particular order of expression evaluation in if. So behavior will be compiler specific and using this style of coding not portable. You face that problem because incrementing/decrementing of value is post operation, but standard says as post operation of expression where variable is used. So if a compiler considers that your expression is just single variable usage as x or y, then you will see one result. If a compiler thinks that expression is entire if expression evaluation, then you will see other result. I hope it helps.



来源:https://stackoverflow.com/questions/6783105/does-the-order-of-operations-change-within-an-if-expression

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