В Си с этим никаких проблем
Это неправда.
C standard, 6.5.2 писал(а):
If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.
89) This paragraph renders undefined statement expressions such as
Т.е. в стандарте прямым текстом написано, что это выражение - UB.
Стоит справа от знака равенства префиксный инкремент на эту ячейку? Увеличиваем значение. ... Куда пишем результат? Туда же? Отлично!
Никто не гарантирует, что запись результата в
i произойдет "до" увеличения значения.
Вообще нельзя думать, что переменная - это такая коробка, в которой в каждый момент лежит какое-то значение, и если туда что-то положили, то именно оно в ней и лежит, пока туда не положат что-то еще. Это хорошо видно с многопоточностью:
x = y = 0;
// Thread 1:
r1 = y.load(std::memory_order_relaxed); // A
x.store(r1, std::memory_order_relaxed); // B
// Thread 2:
r2 = x.load(std::memory_order_relaxed); // C
y.store(42, std::memory_order_relaxed); // D
Имеет полное право выдать
r1 == 42, r2 == 42, хотя 1) никакое чередование выполнения первого и второго потоков не может дать такой результат; 2) стандарт гарантирует, что каждый отдельный поток работает так как будто выражения выполняются в том порядке, в котором записаны.