2012-04-29 3 views
3

Я смущен о выходе этого кода:Почему (C++) * (C++) неопределенное поведение в C++?

int c=3; 
cout<<(c++)*(c++); 

Я использую GCC и выход 9, но кто-то сказал, что это неопределенное поведение, почему?

+8

Ну, это C++ не c –

+0

Тот же результат, такая же проблема, либо C, либо C++ – paulsm4

+2

@ paulsm4 Не совсем. В C это очень специфическое определенное поведение: вы получаете ошибку компилятора. –

ответ

4

Этот вопрос «Последовательность точек»:

http://en.wikipedia.org/wiki/Sequence_point

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

Точки последовательности также вступают в игру, когда одна и та же переменная изменяется более одного раза в одном выражении. Часто цитируемый пример: выражение C i = i ++, которое, по-видимому, оба присваивает i его предыдущее значение и увеличивает i. Конечное значение i неоднозначно, потому что в зависимости от порядка оценки выражения, приращение может происходить до, после или чередуется с назначением. В определении определенного языка может указываться одно из возможных действий или просто сказать, что поведение не определено. В C и C++ оценка такого выражения дает неопределенное поведение. [1]

Как бы то ни было, я получаю точно такой же ответ - «9» - как на MSVC (Windows), так и на gcc (Linux). Я также получаю предупреждение компилировать ли я с GCC («C») или г ++ (C++):

$ g++ -o tmp -Wall -pedantic tmp.cpp 
tmp.cpp: In function "main(int, char**)": 
tmp.cpp:7: warning: operation on "c" may be undefined 
$ ./tmp 
c=9... 
+0

И на 'tcc' и' clang' я получаю '12'. :) – Jack

1

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

Например, вычисляется умножением первой последующей обоих ++ х годов, или один ++ сначала вычисляется, то умножение, то другой ++?

+0

Порядок оценки - это не неопределенное поведение - это неуказанное поведение. Разница заключается в том, что компилятор не может делать все, что он хочет - он все равно должен правильно оценивать выражение. Это просто не нужно выполнять эту оценку в каком-либо конкретном порядке (за исключением определенных операций, которые налагают порядок). С другой стороны, выражение 'i + = ++ i' не определено - там * не корректно, а компилятор может делать все, что захочет. –

3

Не определено поведение ничего может случиться.

Выход 9, но с разными компиляторами или различными ключами компилятора, это также может быть 12, 0 или 2147483647.

+0

И он может отформатировать ваш жесткий диск! – orlp

0

В зависимости от того, как написан компилятор, какие флаги используются для компиляции, фаза луны и т. Д., Ответ может быть 9, 16, 20, или он может произвести nasal demons. Всегда старайтесь избегать запутывания кода и неопределенного поведения. Посмотрите на пункты последовательности о том, как этого избежать.

+0

ОК, я буду кусать. Я ожидал бы 9, 12 или 16, так как вы получите 20? –

+0

@Mr. Листер: это характер неопределенного поведения. –

0

Один из способов мышления о точках последовательности и почему ваш пример имеет как unspecified behavior и undefined behavior это, рассматривая выполнение которых первый вводит временные переменные:

Такая реализация может обрабатывать после приращения следующим образом:

tmp_1=c;    // read 'c' 
tmp_2 = tmp_1 + 1; // calculate the incremented value 
c = tmp_2;   // write to 'c' 
tmp_1;    // the result of the expression 

Исходное выражение (c++)*(c++) имеет две последовательности:

lhs_1=c;    // read 'c' 
lhs_2 = lhs_1 + 1; // calculate the incremented value 
c = lhs_2;   // write to 'c' 
lhs_1;    // the resulting value of the expression 

rhs_1=c;    // read 'c' 
rhs_2 = rhs_1 + 1; // calculate the incremented value 
c = rhs_2;   // write to 'c' 
rhs_1;    // the resulting value of the expression 

Заказ может быть:

lhs_1=c;    // read 'c' 
lhs_2 = lhs_1 + 1; // calculate the incremented value 
c = lhs_2;   // write to 'c' 

rhs_1=c;    // read 'c' 
rhs_2 = rhs_1 + 1; // calculate the incremented value 
c = rhs_2;   // write to 'c' 

lhs_1 * rhs_1   // (3 * 4) new value of 'c' is 5 

Или:

lhs_1=c;    // read 'c' 
rhs_1=c;    // read 'c' 

lhs_2 = lhs_1 + 1; // calculate the incremented value 
c = lhs_2;   // write to 'c' 

rhs_2 = rhs_1 + 1; // calculate the incremented value 
c = rhs_2;   // write to 'c' 

lhs_1 * rhs_1   // (3 * 3) new value of 'c' is 4 

Или:

rhs_1=c;    // read 'c' 
rhs_2 = rhs_1 + 1; // calculate the incremented value 
c = rhs_2;   // write to 'c' 

lhs_1=c;    // read 'c' 
lhs_2 = lhs_1 + 1; // calculate the incremented value 
c = lhs_2;   // write to 'c' 

lhs_1 * rhs_1   // (4 * 3) new value of 'c' is 5 

.... и т.д..

unspecified behavior в том, что он может сначала оценить lhs или rhs. undefined behavior состоит в том, что мы читаем и записываем c без промежуточных точек последовательности.

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