2016-03-19 2 views
3

Я смущен о выходе кода. Это зависит от того, какой компилятор я запускаю код. Почему это так?Как мы можем предсказать вывод следующей программы на C++

#include <iostream> 
using namespace std; 
int f(int &n) 
{ 
    n--; 
    return n; 
} 
int main() 
{ 
     int n=10; 
     n=n-f(n); 
     cout<<n; 
     return 0; 
} 

Запуск его на терминале Ubuntu с г ++, выход 1, тогда как запустить его на Turbo C++ (компилятор мы использовали в школе) дает результат, как 0.

ответ

4

В C++ 03, модифицируя переменная, а также ее значение в том же выражении без промежуточной C++ 03 точка последовательности, была Неопределенное поведение.

03 § 5/4 С ++:

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

Undefined Behavior, UB, предоставляет компилятору возможность оптимизировать, поскольку он может предположить, что UB не встречается в действительной программе.

Однако, несмотря на все бесчисленные правила UB на C++, сложно объяснить исходный код.


В C++ 11 точек последовательности были заменены секвенированы перед тем, секвенировали неопределенно и unsequenced отношений:

C++ 11 §1.9/3

При любых двух оценках A и B, если A секвенирован до B, то выполнение A должно предшествовать исполнению B. Если не секвенирован перед тем B и B не секвенирован перед тем , затем и B является unsequenced. [Примечание: Выполнение необследованных оценок может перекрываться.-end примечание] Оценки и B являются секвенировали неопределенно, когда либо секвенируют, прежде чем B или B секвенируют, прежде чем , но это не определено, который.

А с новыми отношениями последовательности C++ 11 правил модификации в функции в коде в вопросе неопределенно секвенировали в отношении использования переменной, и поэтому код имеет неопределенное поведение, а не Неопределенное поведение, как отметил Эрик М Шмидт в a comment to (the first version of) this answer. По сути, это означает, что нет опасности носовых демонов или других возможных эффектов UB, и что поведение является разумным. Двумя возможными поведением здесь являются то, что модификация через вызов функции выполняется до использования значения или что это делается после использования значения.

Почему это не определенно поведение:

C++ 11 §1.9/15:

Каждой оценка в вызывающей функции (в том числе других вызовов функций), не иначе конкретно секвенировал до или после выполнения тела вызываемой функции неопределенно секвенируется с в отношении выполнения вызываемой функции.

Что “ неопределенное поведение ” означает:

C++ 11 §1.3.25:

неопределенного поведение
поведение, для хорошо сформированной конструкции программы и правильных данных, что зависит от реализации [Примечание: Реализация не требуется для документирования поведения. Диапазон возможного поведения обычно определяется в этом международном стандарте. -end примечание]

Почему модификация осуществляется путем присвоения не является проблематичной:

C++ 11 §5.17/1

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

Это также сильно отличается от C++ 03.


Поскольку довольно резкое изменение этого ответа показывает, что после комментария Эрика этот вопрос не прост!Главный совет, который я могу дать, - это максимально просто сказать «Нет» ™ эффектам, управляемым тонкими или очень сложными правилами, углами языка. У простого кода есть больше шансов быть верным, в то время как так называемый умный код не имеет хороших шансов быть значительно быстрее.

+0

Данный код не имеет неопределенного поведения, просто неопределенного поведения. –

+0

@EricMSchmidt: Это интересная идея. В терминах C++ 11 вы говорите, что вызов функции не имеет «побочного эффекта на скалярном объекте» здесь, или вы говорите, что это не является необъективным относительно использования этого объекта? –

+0

Это не является необъективным, а скорее неопределенным, потому что операция декремента происходит в функции f, а не в основной. «Каждая оценка в вызывающей функции (включая другие вызовы функций), которая иначе не секретируется отдельно до или после выполнения тела вызываемой функции, неопределенно упорядочена в отношении выполнения вызываемой функции». (1,9/15) –

Смежные вопросы