Why does "++x || ++y && ++z" calculate "++x" first, even though operator "&&" has higher precedence than "||"
Solution 1:
Huh?
If you're saying that &&
binds tighter than ||
(which is true), the expression is then equivalent to
++x || (++y && ++z)
Since ||
short-circuits, it needs to evaluate the left-hand side first.
If you mean that it ought to be equivalent to
(++x || ++y) && ++z
The same is still true, since &&
also short-circuits, meaning the ||
needs to be evaluated first, which in turn makes ++x
the first thing to evaluate.
Solution 2:
Since &&
has higher precedence than ||
, it means your expression is equivalent to:
++x || (++y && ++z)
Thus, before the program even begins evaluating the result of &&
, it has to evaluate ++x
to determine whether the right-hand operand of ||
should even be evaluated (logical binary operators are "short-circuiting", meaning they do not evaluate the right-hand side if the left-hand side is sufficient to determine the result). There is nothing fishy or compiler-specific here. The behavior of this expression is specified exactly by the C standard and will be the same on any compiler. It would even work if x
, y
, and z
were all the same variable, since ||
and &&
introduce sequence points.
Solution 3:
Unwind, R and others have explained what really happens. So let me just add:
The premise of your question is faulty. The fact that the &&
has higher precedence doesn't mean that operands that surround it must be evaluated before any operands in the expression with lower precedence. Even where the special case short-circuiting of ||
and &&
this wouldn't necessarily be so.
For example, consider a=b+c+d*e
; *
has higher precedence than +
, but that doesn't mean that d*e
must be evaluated before b+c
. It just means that it must be evaluated before we add the product to the expression as a whole. A compiler could evaluate this expression as temp1=d*e
, temp2=b+c
, a=temp1+temp2
or it could evaluate temp1=b+c
, temp2=d*e
, a=temp1+temp2
. Both would be equally valid.
With the short-circuiting behavior of ||
and &&
, there are some additional restrictions placed on order of evaluation.
As a side note: In general I would avoid writing code like this. I can easily see another programmer trying to read this code getting confused about just when the increments will happen and when they won't. Well, maybe if you used real variable names it would not look so bizarre.
I do occasionally rely on short-circuiting preventing side effects. Like
if (!eof() && readNextInt()>0)
I'm relying on the short-circuit to prevent reading if we're already at end of file, Or
if (confirmDelete==YES && deleteEntry()!=-1)
I'm relying on the first test to short-circuit on false so I don't do the delete when I shouldn't. But these examples seem pretty straightforward to me, I'd hope any competent programmer would see what I'm doing. But when the examples get cryptic, I think it needs to be broken out. Consider
if (customerType==RETAIL || lastDepositAmount()>100.00)
If lastDepositAmount()
had a side effect, then if customerType
is retail this side effect will never happen. I don't think that would necessarily be obvious to a reader. (Partly because the function name implies that it is retrieving data and not performing any update, and partly because there is no obvious relationship between the customer type and the amount of a deposit -- these sound like two independent things.) Admittedly, this is subjective. But when in doubt, choose simplicity and clarity over a trivial performance improvement. Always choose simplicity and clarity over "hey this is a way cool use of an obscure feature, anyone reading this will be impressed at how smart I must be to understand the language well enough to do this".
Solution 4:
There are horribly wrong answers here.
The order of evaluation of this expression is not implementation dependent. It is well-defined!
Since &&
binds higher than ||
, this expression is equivalent to ++x || (++y && ++z)
. Furthermore, both &&
and ||
are short-circuited, so if the left-hand side of the expression suffices to determine the value, the right-hand side is never evaluated.
When is this the case? Well, we know that False && a
always resolves to False
, no matter the value of a
, in particular even if a
is not a single value but instead a complex expression. Therefore we don’t evaluate a
at all. Likewise, True || a
always resolves to True
.
This results in a very definite order of evaluation in this example: first ++x
, then (if at all) ++y
and then (again: if at all) ++z
.
Solution 5:
The operators are evaluated using the Polish tree datastructure, as in the diagram, and it's a depth-first evaluation algorithm. Let's give names to the operations: A = ++x B = ++y C = ++z D = B && C E = C || D Evaluation order: A, B, C, D, E. Of course, C has an optimisation and if A is true, then E will be evaluated as true without evaluating B C and D. Similarly, if B is false, then C won't be evaluated to optimize the evaluation speed.