Является ли (--i == i ++) неопределенным поведением? - PullRequest
0 голосов
/ 14 марта 2011

этот вопрос связан с моей предыдущей проблемой .Ответ, который я получил, был «Это неопределенное поведение».

Пожалуйста, кто-нибудь объяснит:

  • Что такое неопределенное поведение?
  • Как я могу узнать, что мой код имеет неопределенное поведение?

Пример кода:

int i = 5;
if (--i == i++)         
   Console.WriteLine("equal and i=" + i);           
else
   Console.WriteLine("not equal and i=" + i);

//output: equal and i=6

Ответы [ 8 ]

2 голосов
/ 14 марта 2011

Это не определено в C, но четко определено в C #:

Из спецификации C # (ECMA-334) раздела «Приоритет оператора и ассоциативность» (§14.2.1):

  • За исключением операторов присваивания и оператора объединения нулей, все двоичные операторы являются левоассоциативными, что означает, что операции выполняются слева направо.[Пример: x + y + z оценивается как (x + y) + z.конец примера]

Итак, --i сначала оценивается, изменяя i на 4 и оценивая до 4. Затем i++ оценивает, изменяя i на 5, но оцениваядо 4.

2 голосов
/ 14 марта 2011

Что такое неопределенное поведение?

Это просто любое поведение, которое не определено соответствующей спецификацией языка. Некоторые спецификации перечисляют определенные вещи как явно неопределенные, но на самом деле все, что не описано как определяемое, не определено.

как я могу узнать, что мой код имеет неопределенное поведение?

Надеюсь, ваш компилятор предупредит вас - если это не так, вам нужно прочитать спецификацию языка и узнать обо всех забавных угловых примерах и хитросплетениях, которые вызывают проблемы такого рода.

Будь осторожен!

1 голос
/ 14 марта 2011

В C результат не определен, в C # он определен.

В C сравнение интерпретируется как:

Делайте все это в любом порядке:
- Уменьшите i, затем получите значение i в x
- Получить значение i в y, затем увеличить i
Затем сравните x и y.

В C # больше границ операций, поэтому сравнение интерпретируется как:

Уменьшить i
затем получить значение i в x
затем получите значение i в y
затем увеличьте i
затем сравните x и y.

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

1 голос
/ 14 марта 2011

(Это предполагает C или C ++.)

Ответ Карла в целом точен.

В частности, проблема заключается в том, на что указал Иеремия: точки последовательности .

Для пояснения, фрагмент кода (--i == ++ i) - это одно "событие".Это кусок кода, который оценивается сразу.Там нет определенного порядка того, что происходит в первую очередь.Левая сторона может быть оценена в первую очередь, или правая сторона может, или, может быть, сравнивается равенство, затем i увеличивается, затем уменьшается.Каждое из этих действий может привести к тому, что это выражение будет иметь разные результаты.«Не определено», что здесь произойдет.Вы не знаете, каким будет ответ.

Сравните это с утверждением i = i + 1;Здесь сначала всегда оценивается правая сторона, затем ее результат сохраняется в i.Это четко определено.Нет никакой двусмысленности.

Надеюсь, это немного поможет.

1 голос
/ 14 марта 2011

Да, это выражение также является неопределенным поведением (в C и C ++).См. http://en.wikipedia.org/wiki/Sequence_point для получения некоторой информации о правилах;вы также можете искать «точку последовательности» в более широком смысле (это набор правил, который нарушает ваш код).

0 голосов
/ 14 марта 2011

Неопределенное поведение == нельзя гарантировать, что результат всегда будет одинаковым, когда вы запускаете его в точно одинаковых условиях, или нельзя гарантировать, что результат всегда будет одинаковым, когда вы используете разные компиляторы или среды выполнения для его выполнения.

В вашем коде, поскольку он использует оператор сравнения равных, который не определяет , какая сторона операндов должна быть выполнена первой, --i или i++ может закончиться выполнением первой, а ваш Ответ будет зависеть от фактической реализации компилятора. Если --i выполняется первым, это будет 4 == 4, i = 5; если i++ будет реализован первым, это будет 5 == 5, i = 5.

Тот факт, что ответ может оказаться таким же, не мешает компилятору предупредить вас, что это неопределенная операция.

Теперь, если это язык, который определяет, что левая сторона (или правая сторона) всегда должна выполняться в первую очередь, то поведение больше не будет неопределенным.

0 голосов
/ 14 марта 2011

Ваш предыдущий вопрос был помечен [C], поэтому я отвечаю на основе C, хотя код в вашем текущем вопросе не похож на C.

Определение неопределенного поведения в C99 гласит (§3.4.3):
1 неопределенное поведение
поведение при использовании непереносимой или ошибочной программной конструкции или ошибочных данных, к которым настоящий международный стандарт не предъявляет никаких требований

2 ПРИМЕЧАНИЕ. Возможное неопределенное поведение варьируется от полного игнорирования ситуации с непредсказуемыми результатами до поведения во время перевода или выполнения программы документированным образом, характерным для среды (с выдачей или без выдачи диагностического сообщения), до прекращения перевода или выполнение (с выдачей диагностического сообщения).

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

0 голосов
/ 14 марта 2011

Потому что стандарт C так утверждает. И ваш пример ясно показывает неопределенное поведение.

В зависимости от порядка оценки, сравнение должно быть 4 == 5 или 5 == 6. И все же условие возвращает True.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...