Каков результат += в C и 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

Но если я скомпилирую его как исходный код C++, используя g++, я не получаю ошибки, и когда я запускаю исполняемый файл:

i = 20

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

2 ответа

Решение

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

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

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

В C++ 5.17.1:

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

РЕДАКТИРОВАТЬ: поведение (i+=10)+=10 в C++ не определен в C++98, но хорошо определен в C++11. Смотрите этот ответ на вопрос NPE для соответствующих частей стандартов.

В дополнение к недействительному коду C, строка

(i+=10)+=10;

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

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

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

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

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

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

Другие вопросы по тегам