Каков результат + = в C и С++?

У меня есть следующий код:

#include <stdio.h>
int main(int argc, char **argv) {
    int i = 0;
    (i+=10)+=10;
    printf("i = %d\n", i);
    return 0;
}

Если я попытаюсь скомпилировать его как источник C с помощью gcc, я получаю сообщение об ошибке:

error: lvalue required as left operand of assignment

Но если я скомпилирую его как источник С++ с помощью g++, я не получаю ошибки и при запуске исполняемого файла:

i = 20

Почему различное поведение?

Ответ 1

Семантика сложных операторов присваивания различна в C и С++:

Стандарт C99, 6.5.16, часть 3:

Оператор присваивания сохраняет значение в объекте, обозначенном левым операндом. выражение присваивания имеет значение левого операнда после назначения, но не является именующий.

В С++ 5.17.1:

Оператор присваивания (=) и составные операторы присваивания все группы справа налево. Все требуют модификации lvalue в качестве своего левого операнда и вернуть значение lvalue с типом и значением левого операнда после выполнения задания.

EDIT: Поведение (i+=10)+=10 в С++ - это undefined в С++ 98, но хорошо определенное в С++ 11. См. этот ответ на вопрос NPE для соответствующих частей стандартов.

Ответ 2

Помимо недействительного кода C, строка

(i+=10)+=10;

приведет к поведению undefined как в C, так и в С++ 03, потому что он дважды изменит i между точками последовательности.

Что касается того, почему это разрешено компилировать в С++:

[С++ N3242 5.17.1] Оператор присваивания (=) и составные операторы присваивания все группы справа налево. Все требуют модифицируемое значение lvalue как его левый операнд и возвращает lvalue, ссылаясь на левый операнд.

В этом же пункте говорится, что

Во всех случаях назначение упорядочивается после значения вычисление правого и левого операндов и перед вычислением значения выражения присваивания.

Это говорит о том, что в С++ 11 выражение больше не имеет поведения undefined.