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:
- Evaluate
++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.
- Otherwise, evaluate
++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