Я смущен о выходе этого кода:Почему (C++) * (C++) неопределенное поведение в C++?
int c=3;
cout<<(c++)*(c++);
Я использую GCC и выход 9
, но кто-то сказал, что это неопределенное поведение, почему?
Я смущен о выходе этого кода:Почему (C++) * (C++) неопределенное поведение в C++?
int c=3;
cout<<(c++)*(c++);
Я использую GCC и выход 9
, но кто-то сказал, что это неопределенное поведение, почему?
Этот вопрос «Последовательность точек»:
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...
И на 'tcc' и' clang' я получаю '12'. :) – Jack
С спецификацией оставляет много вещей неопределенной, и они в значительной степени остаются на усмотрение того, кто реализует язык (т.е. записывает компилятор). Среди этих неопределенных вещей - порядок оценки различных частей выражения.
Например, вычисляется умножением первой последующей обоих ++
х годов, или один ++
сначала вычисляется, то умножение, то другой ++
?
Порядок оценки - это не неопределенное поведение - это неуказанное поведение. Разница заключается в том, что компилятор не может делать все, что он хочет - он все равно должен правильно оценивать выражение. Это просто не нужно выполнять эту оценку в каком-либо конкретном порядке (за исключением определенных операций, которые налагают порядок). С другой стороны, выражение 'i + = ++ i' не определено - там * не корректно, а компилятор может делать все, что захочет. –
Не определено поведение ничего может случиться.
Выход 9
, но с разными компиляторами или различными ключами компилятора, это также может быть 12
, 0
или 2147483647
.
И он может отформатировать ваш жесткий диск! – orlp
В зависимости от того, как написан компилятор, какие флаги используются для компиляции, фаза луны и т. Д., Ответ может быть 9, 16, 20, или он может произвести nasal demons. Всегда старайтесь избегать запутывания кода и неопределенного поведения. Посмотрите на пункты последовательности о том, как этого избежать.
ОК, я буду кусать. Я ожидал бы 9, 12 или 16, так как вы получите 20? –
@Mr. Листер: это характер неопределенного поведения. –
Один из способов мышления о точках последовательности и почему ваш пример имеет как 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
без промежуточных точек последовательности.
Ну, это C++ не c –
Тот же результат, такая же проблема, либо C, либо C++ – paulsm4
@ paulsm4 Не совсем. В C это очень специфическое определенное поведение: вы получаете ошибку компилятора. –