Your reasoning goes wrong in the fact that the sub-expression
i++ has two steps that don't necessarily have to be executed immediately after each other.
- The first step is yielding the original value of
i for further computations
- The second step is storing the new (incremented) value back to
There is nothing preventing an optimising compiler from putting other computations (like the assignment to
i) in between those two steps. As storing a value in
i can even take multiple machine instructions, the instructions from the assignment and from storing the result of the increment could become interleaved with each other, possibly yielding an end result that neither resembles the incremented nor the original value.