Как объяснить результат выражения (++ x) + (++ x) + (++ x)?

x = 1;
std::cout << ((++x)+(++x)+(++x));

Я ожидаю, что результат будет 11, но на самом деле это 12. Почему?


person Rohit Banga    schedule 06.10.2009    source источник
comment
Я ожидал, что это будет 9 ...: /   -  person anonymous coward    schedule 06.10.2009
comment
@Charlie: Некоторые компиляторы могут это делать :)   -  person Artelius    schedule 06.10.2009
comment
Я бы ожидал жертвоприношения козла, прежде чем полагаться на такой код.   -  person György Andrasek    schedule 06.10.2009
comment
@Jurily хотел узнать поведение компилятора   -  person Rohit Banga    schedule 06.10.2009
comment
Я все еще хотел бы услышать, почему вы ожидаете, что результат будет 11 ...   -  person Ed S.    schedule 22.11.2009
comment
Интересный. Просто попробовал это в консоли JavaScript. Ответ - 9 в Chrome.   -  person Nosredna    schedule 22.11.2009
comment
@Nosredna: Вы знаете, что этот вопрос касается поведения этого фрагмента кода на C ++, а не на Javascript, верно? На языке, который я только что придумал, (++x)+(++x)+(++x) заставляет компьютер выдвигать лоток для DVD. Но поскольку это не C ++, это не относится к этому вопросу. ;)   -  person jalf    schedule 22.11.2009
comment
Я прокомментировал это в основном потому, что Чарли Сомервилль ожидал 9. В ответах довольно четко установлено, что в C ++ результат не определен. Так что теперь мне интересно, что делают другие языки, производные от C-синтаксиса.   -  person Nosredna    schedule 22.11.2009
comment


Ответы (5)


Мы объясняем это ожиданием неопределенного поведения, а не какого-либо конкретного результата. Поскольку выражение пытается изменить x несколько раз без вмешательства точки последовательности, его поведение не определено.

person CB Bailey    schedule 06.10.2009
comment
+1 Я только что пробовал это с помощью gcc 3.2.2 в Linux, и выражение возвращает 10 (9 и 12 съедают вам сердце ...) - person Todd Owen; 06.10.2009
comment
Вот хорошее описание точки последовательности imho в руководстве GCC: gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/ - person Johannes Schaub - litb; 06.10.2009
comment
Тогда почему это не синтаксическая ошибка? Любая двусмысленность, которая превращается в скомпилированный код ... кажется недосмотром. - person Alex Feinman; 06.10.2009
comment
@Alex Feinman: принуждение соответствующих реализаций к диагностике ошибки ложится дополнительным бременем на разработчиков. Вопрос о том, перевешивает ли эта стоимость выгоду для пользователей. Часто стандарт C ++ сводится к тому, чтобы не обременять разработчиков без надобности. Учитывая сложность написания реализации на C ++, это может быть неплохо. - person CB Bailey; 06.10.2009
comment
@Alex Feinman: Это все равно что спросить, почему это не синтаксическая ошибка: MyClass & ptr = NULL; ptr- ›doSomething (); Потому что никто, кто знает лучше, не напишет этого. - person Bill; 06.10.2009
comment
@Bill: это не совсем то же самое, что спрашивать об этом, поскольку ваш пример требует анализа DFA, тогда как несколько подвыражений выражения, которые изменяют одну и ту же переменную и не разделены в полном выражении точкой последовательности, по крайней мере теоретически диагностируются только с помощью локальный анализ выражения. Но способ, которым стандарт C ++ выражает правило, заключается в том, что любой допустимый порядок выполнения выражения не имеет разделителя точки последовательности, и вполне разумно ожидать, что реализации не будут приводить аргументы в отношении всех законных порядков выполнения. - person Steve Jessop; 06.10.2009
comment
... и в любом случае, хотя этот пример с повторным использованием x на самом деле не так уж сложно диагностировать, если бы в выражении могли быть псевдонимы, то это было бы так. Часто половина работы по выявлению ошибок хуже, чем ее отсутствие, поскольку это побуждает людей ошибочно думать, что им не нужно думать об этом классе ошибок, потому что компилятор сделает это за них. - person Steve Jessop; 06.10.2009

Как уже говорили другие, стандарты C и C ++ не определяют поведение, которое это приведет.

Но для тех людей, которые не понимают, почему стандарты делают такое, давайте рассмотрим пример из «реального мира»:

1 * 2 + 3 + 4 * 5

Нет ничего плохого в вычислении 1 * 2 + 3 до вычисления 4*5. Тот факт, что умножение имеет более высокий приоритет, чем сложение, не означает, что нам нужно выполнить все умножение в выражении перед выполнением любого сложения. На самом деле существует множество различных заказов, по которым вы действительно могли бы выполнять свои расчеты.

Если у оценок есть побочные эффекты, разные порядки оценки могут повлиять на результат. Если стандарт не определяет поведение, не полагайтесь на него.

person Artelius    schedule 06.10.2009
comment
тогда в чем польза приоритета оператора. я не понимаю ваш пример: 1 * 2 + 3 + 4 * 5 = (1 * 2) + 3 + (4 * 5) нет? - person Rohit Banga; 06.10.2009
comment
или более простой пример: 1 * 2 + 3 * 4 = (1 * 2) + (3 * 4) - person Rohit Banga; 06.10.2009
comment
(1 * 2 + 3) + (4 + 5) == (1 * 2) + (3 + 4 * 5). существует более чем один способ упорядочить выполнение, так что порядок операций по-прежнему сохраняется. math не имеет состояния, но если операция влияет на состояние, вы должны указать последовательность выполнения более конкретно. - person Dustin Getz; 06.10.2009
comment
@Dustin Getz: Технически грамматика C ++ указывает, что выражение должно быть (((1 * 2) + 3) + (4 * 5)), а не ((1 * 2) + (3 + (4 * 5))) но вы правы, порядок расчета может быть 1 * 2, 4 * 5, (1 * 2) +3, ((1 * 2) + 3) + (4 * 5) или 1 * 2, (1 * 2 ) + 3, 4 * 5, ((1 * 2) + 3) + (4 * 5) или ряд других возможностей, включая независимые части, выполняемые параллельно. - person CB Bailey; 06.10.2009

На самом деле это не определено. C ++ явно не определяет порядок выполнения оператора, поэтому он зависит от компилятора, и этот синтаксис использовать не следует.

person Julien Lebosquain    schedule 06.10.2009
comment
На самом деле это хуже, чем просто неуказанный порядок выполнения (что просто означает, что вы не знаете, какой будет ответ), в этом случае поведение не определено (поэтому вы не знаете, загорится ли ваш компьютер). - person Steve Jessop; 06.10.2009

Фрагмент кода вызовет неопределенное поведение в обоих языках C / C ++. Подробнее о точке последовательности читайте в здесь.

person whacko__Cracko    schedule 22.11.2009

На мой взгляд

cout<<((++x)+(++x)+(++x));

компилятор сначала запускает префикс ++ x, поэтому значение x становится

x=2


теперь к ++ x, x станет

x=3


после ++ x

x=4


Теперь пришло время добавить значения x

x+x+x=4+4+4

x+x+x=12

person Mohsin Ammar    schedule 23.02.2015
comment
Мнения - это не ответы. Это также противоречит тому, что уже было отмечено как правильный ответ: undefined - person Jan Doggen; 23.02.2015
comment
Я только сказал, что приведенное выше выражение не означает 2 + 3 + 4, потому что сначала изменяется значение x, а затем оно добавляется. означает, что 2 + 3 + 4 не является ответом, но на самом деле складывается вот так 4 + 4 + 4. - person Mohsin Ammar; 23.02.2015
comment
Хотя другие ответы могут быть технически подходящими в общем смысле, это единственный ответ, который на самом деле объясняет, почему 12 является логическим результатом. Итак, +1 за объяснение, даже если это странный образец, которому не следует следовать на практике. На мой взгляд, это в сочетании с другими ответами - это то, что действительно требуется для полного ответа на исходный вопрос. Объяснение того, почему это не единственный способ интерпретации, также было бы хорошим дополнением к аспекту неопределенного поведения. - person thesquaregroot; 21.03.2018