Действительно ли поведение я = i++ не определено?
Возможный дубликат:
Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)
Согласно стандарту С++,
i = 3;
i = i++;
приведет к поведению undefined.
Мы используем термин "поведение undefined", если это может привести к более чем одному результату. Но здесь конечное значение i
будет равно 4 независимо от порядка оценки, так разве это не следует называть "неуказанным поведением"?
Ответы
Ответ 1
Фраза "... окончательное значение i
будет 4 независимо от того, какой порядок оценки..." неверен. Компилятор может испустить эквивалент этого:
i = 3;
int tmp = i;
++i;
i = tmp;
или это:
i = 3;
++i;
i = i - 1;
или это:
i = 3;
i = i;
++i;
Что касается определений терминов, если бы ответ был гарантирован 4, это не было бы неуказанным или undefined поведением, было бы определено поведение.
В соответствии с этим, это undefined поведение в соответствии со стандартом (Wikipedia), поэтому он даже свободен для этого:
i = 3;
system("sudo rm -rf /"); // DO NOT TRY THIS AT HOME … OR AT WORK … OR ANYWHERE.
Ответ 2
Нет, мы не используем термин "поведение undefined", когда оно может просто привести к более чем одному арифметическому результату. Когда поведение ограничено различными арифметическими результатами (или, в более общем плане, некоторым набором прогнозируемых результатов), его обычно называют неуказанным поведением.
Undefined поведение означает совершенно непредсказуемые и неограниченные последствия, такие как форматирование жесткого диска на вашем компьютере или просто сбой вашей программы. И i = i++
- поведение undefined.
Если у вас возникла идея, что i
должно быть 4 в этом случае, неясно. На языке С++ нет абсолютно ничего, что позволило бы вам прийти к такому выводу.
Ответ 3
В C, а также в С++ порядок любой операции между двумя точками последовательности полностью зависит от компилятора и не может зависеть. Стандарт определяет список вещей, составляющих точки последовательности, из памяти это
- точка с запятой после утверждения
- оператор запятой
- оценка всех аргументов функции перед вызовом функции
- && и || Операнд
Поднимая страницу по wikipedia, списки более полные и описывают более подробно. Точки последовательности являются чрезвычайно важной концепцией, и если вы еще не знаете, что это значит, вы получите большую пользу, изучив ее сразу.
Ответ 4
i =, а я ++ - оба побочных эффекта, которые изменяют i.
i ++ не означает, что я увеличивается только после того, как весь оператор оценивается, просто чтобы было прочитано текущее значение i.
Таким образом, назначение и приращение могут происходить в любом порядке.
Ответ 5
1.
Нет, результат будет отличаться в зависимости от порядка оценки. Границы оценки между приращением и присваиванием отсутствуют, поэтому приращение может быть выполнено до или после назначения. Рассмотрим это поведение:
load i into CX
copy CX to DX
increase DX
store DX in i
store CX in i
В результате i
содержит 3
, а не 4
.
В качестве сравнения в С# существует граница оценки между evaulation выражения и присваиванием, поэтому результат всегда будет 3
.
2.
Даже если точное поведение не указано, спецификация очень понятна в отношении того, что она покрывает и что она не охватывает. Поведение указано как undefined, оно не определено.
Ответ 6
Чтобы ответить на ваши вопросы:
- Я думаю, что "поведение undefined" означает, что разработчик компилятора/языка свободен делать все, что он считает лучшим, и не может привести к нескольким результатам.
- Потому что это не неуказанный. Он четко указал, что его поведение undefined.
Ответ 7
Не стоит печатать я = я ++, когда вы можете просто набрать я ++.
Ответ 8
Я видел такой вопрос на практическом тесте OCAJP. Декомпилятор IntelliJ IDEA превращает это
public static int iplus(){
int i=0;
return i=i++;
}
в это
public static int iplus() {
int i = 0;
byte var10000 = i;
int var1 = i + 1;
return var10000;
}
Создайте JAR из модуля, затем импортируйте как библиотеку и проверьте. ![enter image description here]()
Ответ 9
Этот вопрос старый, но, похоже, на него часто ссылаются, поэтому он заслуживает нового ответа в свете изменений в стандарте.
http://eel.is/c++draft/basic.exec
http://eel.is/c++draft/expr.ass
[expr.ass] В подпункте 1 поясняется "... последовательность присваивается после вычисления значения правого и левого операндов..." и "Правый операнд упорядочивается перед левым операндом". Здесь подразумевается, что побочные эффекты правого операнда упорядочиваются перед присваиванием, а это означает, что выражение не рассматривается в соответствии с пунктом [basic.exec], подразделом 10: "Если побочный эффект в ячейке памяти ([ intro.memory]) не секвенируется относительно другого побочного эффекта в той же области памяти или вычисления значения с использованием значения любого объекта в той же области памяти, и они не являются потенциально одновременными ([intro.multithread]), поведение не определено. "
Поведение определяется, как объяснено в следующем примере.