i = ++ я + ++ я; в C++

16
задан Cœur 21 July 2018 в 18:18
поделиться

9 ответов

Порядок побочных эффектов не определен в C++. Кроме того, изменение переменной дважды в отдельном выражении не имеет никакого определенного поведения (См. стандарт C++ , В§5.0.4, физическая страница 87 / логическая страница 73).

Решение: не используйте побочные эффекты в сложном выражении, не используйте больше чем один в простых. И не повреждает включать все предупреждения, которые компилятор может дать Вам: Добавление -Wall (gcc) или /Wall /W4 (Visual C++) к командной строке приводит к установке, предупреждающей:

test-so-side-effects.c: In function 'main':
test-so-side-effects.c:5: warning: operation on 'i' may be undefined
test-so-side-effects.c:5: warning: operation on 'i' may be undefined

, Очевидно, код компилирует в:

i = i + 1;
i = i + 1;
i = i + i;
44
ответ дан 30 November 2019 в 15:06
поделиться

Это - неопределенное поведение, результат будет варьироваться в зависимости от компилятора, который Вы используете. Посмотрите, например, FAQ C++, Облегченный .

16
ответ дан 30 November 2019 в 15:06
поделиться

В некоторых ответах/комментариях была дискуссия о значении 'неопределенного поведения' и делает ли это программу недопустимой. Таким образом, я отправляю этот довольно длинный ответ, детализирующий точно, что стандарт говорит с некоторыми примечаниями. Я надеюсь, что это не слишком скучно...

заключенные в кавычки биты стандарта прибывают из текущего стандарта C++ (ISO/IEC 14882:2003). В стандарте C существует подобная формулировка.

Согласно стандарту C++, изменяя значение несколько раз в ряде результатов точек последовательности в неопределенном поведении (разделяют 5 Абзацев 4):

Кроме, где отмечено, порядок оценки операндов отдельных операторов и подвыражений отдельных выражений, и порядок, в котором происходят побочные эффекты, являются unspecified.53) Между предыдущей и следующей точкой последовательности, что скалярному объекту должна изменить его хранимую сумму самое большее однажды оценка выражения. Кроме того, к предшествующему значению нужно получить доступ только для определения значения, которое будет сохранено. Требованиям этого абзаца нужно отвечать для каждого допустимого упорядочивания подвыражений полного выражения; иначе поведение не определено. [Пример:

i = v[i++]; // the behavior is unspecified
i = 7, i++, i++; // i becomes 9
i = ++i + 1; // the behavior is unspecified
i = i + 1; // the value of i is incremented

— заканчивают пример]

Примечание, что второй пример, "i = 7, i++, i++;" определяется, так как оператор запятой является точкой последовательности.

Вот то, что в стандарте C++ говорится, что 'неопределенное поведение' означает:

1.3.12 неопределенных поведения [defns.undefined]

поведения, те, которые могли бы возникнуть после использования ошибочной конструкции программы или ошибочных данных, для которых этот Международный стандарт не налагает требований. Неопределенное поведение может также ожидаться, когда этот Международный стандарт опустит описание любого явного определения поведения. [Отметьте: допустимое неопределенное поведение колеблется от игнорирования ситуации полностью с непредсказуемыми результатами, к поведению во время перевода или выполнения программы в зарегистрированной характеристике способа среды (с или без выпуска сообщения диагностики), к завершению перевода или выполнения (с выпуском сообщения диагностики). Много ошибочных конструкций программы не порождают неопределенное поведение; они обязаны быть диагностированными.]

, Другими словами, компилятор является бесплатным сделать независимо от того, что он хочет, включая [1 124]

  1. выкладывание сообщения об ошибке,
  2. выполнение чего-то, что реализация определила & зарегистрированный,
  3. имеющие абсолютно непредсказуемые результаты

второй объект покрывает расширения языка, которые большинство компиляторов имеет, но конечно не определяется в стандарте.

, Таким образом, я предполагаю, что строго говоря что-то, что показывает неопределенное поведение, не 'недопустимо', но по моему опыту каждый раз, когда было что-то в программе C/C++, которая показывает 'неопределенное поведение' (если это не расширение) - это - ошибка. Я думаю, что вызов такой недопустимой конструкции не сбивает с толку, является вводящим в заблуждение, или дезинформированный.

кроме того, я думаю, пытаясь объяснить, что компилятор делает для достижения, значение 14 не особенно полезно, поскольку это упускает суть. Компилятор мог делать почти что-либо; на самом деле вероятно, что компилятор может достигнуть различного результата, когда это выполнило использование, отличающееся опции оптимизации (или может произвести код, который отказывает - кто знает?).

Для тех, кто хочет некоторые дополнительные ссылки или обращение к полномочиям, вот некоторые указатели:

Steve Summit (специалист по обслуживанию comp.lang.c Часто Задаваемые Вопросы) долго, длинный ответ по этой теме с 1995:

Вот - то, что Bjarne Stroustrup должен сказать относительно вопроса:

<час>

Сноска : стандарт C++ использует слово, 'недопустимое' точно однажды - при описании различия между C++ и Стандартом C относительно использования static или extern с описаниями типа.

12
ответ дан 30 November 2019 в 15:06
поделиться

Простой... Вы компилятор оценивает ОБА инкременты прежде, чем выполнить сумму, не кэшируя промежуточные результаты. Это означает, что, когда Вы добавляете меня дважды, это теперь имеет значение 7.

, Если Вы делаете

int j=++i; 
int k=++i;

i = j+k;

, Вы будете видеть 13 как ожидалось.

3
ответ дан 30 November 2019 в 15:06
поделиться

На Вашем конкретном компиляторе это принимает решение сделать оба из ++ операции сначала, тогда дополнение. Это интерпретирует код как:

int i = 5;
++i;
++i;
i = i + i;
cout << i;

Это совершенно допустимо.

2
ответ дан 30 November 2019 в 15:06
поделиться

Лучший вопрос был бы, это всегда будет 14?

int i = 5;
i = ++i + ++i;
cout<<i;

i = ++i   + ++i   ;
i = ++(5) + ++(5) ;
i =    6  +    6  ;
i = 12;

i = ++i   + ++i   ;
i = ++i   + ++(5) ;
i = ++i   +   (6) ;
i = ++(6) +    6  ;
i =   (7) +    6  ;
i = 13;

i = ++i   + ++i   ;
i = ++i   + ++(5) ;
i = ++(6) +   (6) ;
i =   (7) +   (7) ;
i = 14;

, По всей вероятности, это, вероятно, будет 14, потому что это делает немного [еще 113] смысл.

1
ответ дан 30 November 2019 в 15:06
поделиться

Я думаю, что при рассмотрении проблемы от вида синтаксического дерева, ответ на проблему становится более четким:

я
|
=
|
+
|
унарное выражение - унарное выражение

унарное выражение: выражение

унарного оператора В нашем case-выражении сводится к переменной i.

Теперь то, что происходит, - то, что оба унарных выражения изменяют тот же операнд, таким образом, код делает два раза ++ я при оценке унарных выражений прежде, чем добавить результаты обоих унарных выражений.

Поэтому то, что делает код, действительно

++ я;
++ я;
я = я + я;

, Поскольку я = 5, который означает

я = я + 1;//я < - 6
я = я + 1;//я < - 7
я = я + я;//я < - 14

1
ответ дан 30 November 2019 в 15:06
поделиться

Поскольку инкремент префикса имеет приоритет:

int i = 5;
i = i+1; // First ++i, i is now 6
i = i+1; // Second ++i, i is now 7
i = i + i // i = 7 + 7
cout << i // i = 14
-1
ответ дан 30 November 2019 в 15:06
поделиться
 i = i++ + i; //11  

 i = i++ + i++; //12

 i = i++ + ++i; //13

 i = ++i + i++; //13

 i = ++i + ++i; //14    
-1
ответ дан 30 November 2019 в 15:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: