The book I use gives associativity of logical operators as right to left, so I expect the result of this code to be 2 2 1
but it is 2 1 1
.
int x,y,z;
x=y=z=1;
z=++x||++y||++z;
printf("%d %d %d",x,y,z);
Why is this?
The book I use gives associativity of logical operators as right to left, so I expect the result of this code to be 2 2 1
but it is 2 1 1
.
int x,y,z;
x=y=z=1;
z=++x||++y||++z;
printf("%d %d %d",x,y,z);
Why is this?
||
has a short-circuit evaluation requirement. If the first operand is different than 0
, then the second operand is not evaluated.
(C11, 6.5.14 Logical OR operator) p4 "If the first operand compares unequal to 0, the second operand is not evaluated."
In your case ++y
and ++z
are never evaluated.
This is a subtle topic. There are 2 types of ordering; evaluation order and associativity. Now it turns out that for &&
and ||
in C, both evaluation and associativity are left-to-right, so your book is wrong. Although the associativity in this case makes no actual difference.
To explain associativity, a || b || c
, if ||
is right-to-left, is seen as a || (b || c)
. But if ||
is left-to-right, it is seen as (a || b) || c
. Well, both produce the same results in all cases. So the associativity of boolean operators doesn't matter (of course, it does matter for some other operators: (a - b) - c
!= a - (b - c)
.
The evaluation order is different; it tells us which order to compare things in after we have applied the implicit brackets from associativity. So with left-to-right evaluation order, a || (b || c)
(and (a || b) || c
) is evaluated in the order a
, then b
, then c
. With right-to-left, both will be evaluated in order c
, b
, a
.
That means even with right-to-left evaluation, you wouldn't see 2 2 1
but rather 1 1 2
. Again regardless of associativity. (edit: actually you would see 1 1 1
, because you're setting z to the result of the expression, which is of course true
)
Another interesting note is that for most operators, evaluation order actually isn't defined. That means (a ++) - (a ++)
is undefined behaviour (thankfully; it would be a nightmare of obfuscation otherwise)
See http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence
or for a less wikipedia page, http://www.difranco.net/compsci/C_Operator_Precedence_Table.htm
Also rule 6 here: http://en.cppreference.com/w/cpp/language/eval_order#Rules (I'm sure it's in the standard but I can only find references for C++03, not C)