A normal language like Java would output 5 in any case and on any machine, but C is known for how little is guaranteed.
Java guarantees that
- a will be incremented, and the new value used as the left operand.
- THEN a will be incremented, and the new value used as the right operand.
- THEN the addition is performed.
The compiler may rearrange the instructions ONLY if that does not affect the result.
C guarantees that
- a will be incremented, and its value (at any point after the increment) will be used as the left operand.
- ALSO a will be incremented, and its value (at any point after the increment) will be used as the right operand.
- THEN the addition is performed.
Turns out that the following is a valid execution order:
++a; ++a; a+a;
In fact, the assembly instructions (highest level of optimisation) may end up:
MOV EAX,[a] ; load the variable
INC EAX ; pre-increment 'a' (left operand)
INC EAX ; pre-increment 'a' (right operand)
MOV [a],EAX ; store 'a' at the last possible moment
SHL EAX,1 ; left-shift by 1 = multiply by 2 = add to itself
; now EAX contains 6.