Reputation: 2149
As far as I'm aware of, unary operators have prior precedence over ||
and &&
. In the following code, I'd expect an output where all outputs are equal to 1. Yes, there is a short-circuit but shouldn't those pre-increments calculated before ||
and &&
? How these precedences work here?
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 0, b = 0, c = 0;
a = b = c == 1;
c = ++a || ++b && ++c; // short-circuit here
printf("a=%d, b=%d, c=%d\n", a, b, c);
}
Output:
a=1 b=0 c=1
Upvotes: 1
Views: 114
Reputation: 5667
The fact that ||
is short-circuiting and the lowest precedence operator explains the result. Because ++
is the higher precedence than &&
and &&
is higher precedence than ||
, the expression tree for ++a || ++b && ++c
is:
|| -- left: ++a
-- right: && --left: ++b
--right: ++c
So, to evaluate the expression, C first considers the rules for evaluating ||
, given by 6.5.14 in the C11 standard. Specifically:
6.5.14.4: Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; if the second operand is evaluated, there is a sequence point between the evaluations of the first and second operands. If the first operand compares unequal to 0, the second operand is not evaluated.
The fact that ||
is short-circuiting means that it evaluates its left operand first and only evaluates its right operand if the left is zero. So to evaluate the expression ++a || ++b && ++c
, C requires the following:
++a
(a
is incremented by one and the expression is equal to its incremented value). If it is non-zero, then ||
expression is equal to 1
and the right side is never evaluated.++b
and ++c
, in left-to-right order. If ++b
is zero, then ++c
is never evaluated. If both are non-zero, then the expression is equal to 1
.Because ++a
evaluates to 1, the right side of the ||
is never evaluated. This is why you have a==1
, b==0
, and c==1
.
There's one additional problem with the statement c = ++a || ++b && ++c
, which is that there's a potential for the statement to invoke undefined behavior. If ++a
is false and ++b
is true, then ++c
has to be evaluated. However, there is no sequence point between c = ...
and ++c
. Since the expressions both modify c
with no sequence point in between, the behavior is undefined. For a further explanation of this see, for example, https://stackoverflow.com/a/3575375/1430833
Upvotes: 2
Reputation: 16935
I think you're confusing operator precedence with order of evaluation. Here's an outline of what happens. In the comments, my use of =
is that of identity - much like the mathematical equals sign.
#include <stdio.h>
#include <stdlib.h>
int main()
{
// all variables are assigned the value 0
int a = 0, b = 0, c = 0;
// a and b are equal to the evaluation of `c == 1`, which is false. a and b are 0
a = b = c == 1;
/*
&& has higher precedence than ||, so ++b and ++c are "grouped": ++a || (++b && ++c)
++a is evaluated, a = 0+1 = 1. 1 is true, short circuit the second grouping.
c = a = 1.
*/
c = ++a || ++b && ++c; // short-circuit here
// a = c = 1, b = 0
printf("a=%d, b=%d, c=%d\n", a, b, c);
}
Upvotes: 1
Reputation: 105992
Operator precedence doesn't have any relation with order of evaluation. Higher precedence means that grouping of operands to that operator is done first.
In the statement
c = ++a || ++b && ++c;
the grouping/binding of the operands of ++
will be done first and then that of &&
and ||
respectively. To show this I am adding parenthesis to the expression
++
has higher precedence so bind operand to it first
c = (++a) || (++b) && (++c);
&&
has higher precedence than ||
c = (++a) || ((++b) && (++c));
||
has higher precedence than =
c = ((++a) || ((++b) && (++c)));
=
has least precedence of all
(c = ((++a) || ((++b) && (++c))));
Upvotes: 3