Это "просто" неопределенное поведение.
Тем не менее, компилятор, вероятно, генерирует код, который читает значение i
один раз, затем выполняет всю арифметику, а затем сохраняет новое значение i
.
Очевидный способ узнать реальное объяснение состоит в том, чтобы взглянуть на сборку, сгенерированную компилятором.