The expression a++ & printf("%d",a)
contains five interesting steps:
- A) read a
- B) increment a
- C) read a
- D) call printf
- E) bitwise-and
You may expect C++ to execute these steps from top to bottom (A->B->C->D->E), because humans tend to read from left to right. But in fact, C++ only gives you the following guarantees:
- A is executed before B (A->B)
- C is executed before D (C->D), because functions need to know their arguments
- A and D are executed before E (A->E, D->E), because operators need to know their operands
- If A is executed before D (A->D), then B is also executed before D (B->D), because
a++
has a side effect, function calls are sequence points, and side effects are guaranteed to be visible by then.
Note that there is no guarantee of the form (A->C) or (B->C). This is what most beginners don't get.
Does C read the value before or after the increment that happens at B? We do not know!
- The operator
&
does not impose any restrictions on the order of evaluation of its operands, so the second operandprintf("%d",a)
may be evaluated before the first operanda++
. (The evaluations of the operands may also be interleaved, as long as they obey the above guarantees.) - Even if the first operand is evaluated before the second operand, the side effect that happens in B is not guaranteed to be visible when C is executed. (It would be visible at D then, because function calls are sequence points, but by then it's too late. The arguments have already been evaluated.)
These restrictions leave us with the following possible execution orders:
- A->B->C->D->E
- A->C->B->D->E
- C->A->B->D->E
- C->D->A->B->E
- C->A->B->D->E
It took me several attempts to write this list down. I am not 100% certain it is correct and complete.