Что именно означают «IB» и «UB»?

111

Я видел, как термины «IB» и «UB» использовались несколько раз, особенно в контексте C ++. Я пробовал поискать их в Google, но очевидно, что эти двухбуквенные комбинации находят много применения. :П

Итак, я спрашиваю вас ... что они имеют в виду, когда говорят, что они плохие?

Chao
источник
5
Если вы решили откатить чужие правки, убедитесь, что орфография, пунктуация и грамматика идеальны. Откатить изменения, которые являются существенным улучшением исходного текста, бессмысленно.
Роберт Харви

Ответы:

140

IB: поведение, определяемое реализацией. Стандарт оставляет за конкретным компилятором / платформой определение точного поведения, но требует, чтобы оно было определено.

Использование поведения, определяемого реализацией, может быть полезным, но делает ваш код менее переносимым.

UB: Неопределенное поведение. Стандарт не определяет, как должна вести себя программа, вызывающая неопределенное поведение. Также известен как «носовые демоны», потому что теоретически он может заставить демонов вылетать из вашего носа.

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

Томас
источник
11
Я все еще жду, когда демон вылетит из чьего-то носа из-за использования неопределенного поведения в C ++. Думаю, это произойдет, когда первые компиляторы будут полностью соответствовать новому стандарту C ++.
OregonGhost
4
@OregonGhost: Думаю, ты прав. Я видел это пару раз с единорогами, но никогда с демонами.
Thomas
33
@OregonGhost - в стандарте не указано, сколько рогов должно быть у демона.
ДВК
5
@ Майкл Берр: Я предпочитаю «загореться». Это явно катастрофично, и у него есть, по крайней мере, смутное впечатление правдоподобия (компьютерное оборудование иногда загорается, по общему признанию, по причинам аппаратного, а не программного сбоя в случае любой системы, о которой вы читаете эту ветку).
Стив Джессоп,
1
Забавно, что ни у кого, ответившего на этот вопрос, репутация меньше 30к.
19

Поведение, определяемое реализацией, и неопределенное поведение

Стандарт C ++ очень специфичен в отношении эффектов различных конструкций, и, в частности, вы всегда должны знать об этих категориях проблем :

  • Неопределенное поведение означает, что нет никаких гарантий. Код может работать, или он может поджечь ваш жесткий диск или заставить демонов вылететь из вашего носа . Что касается языка C ++, то может случиться абсолютно все. На практике это обычно означает, что у вас есть неисправимая ошибка. Если это произойдет, вы не можете действительно доверять ничего о приложении (потому что один из эффектов этого непредсказуемого поведения может просто быть напутают памяти , используемых в остальной части вашего приложения). Необязательно быть последовательным, поэтому повторный запуск программы может дать разные результаты. Это может зависеть от фаз луны, цвета рубашки, которую вы носите, или чего-то еще.

  • Неопределенное поведение означает, что программа должна делать что-то разумное и последовательное, но не требуется документировать это.

  • Поведение, определяемое реализацией, аналогично неопределенному, но также должно быть задокументировано авторами компилятора. Примером этого является результат reinterpret_cast. обычно он просто изменяет тип указателя, не изменяя адрес, но отображение фактически определяется реализацией, поэтому компилятор может отображать совершенно другой адрес, если он задокументировал этот выбор. Другой пример - размер int. Стандарт C ++ не заботится о том, составляет ли он 2, 4 или 8 байтов, но он должен быть задокументирован компилятором.

Но общим для всего этого является то, что их лучше избегать. По возможности придерживайтесь поведения, которое на 100% определяется самим стандартом C ++. Таким образом, вам гарантирована портативность.

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

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

Jalf
источник
1
UB следует избегать, если вы заботитесь о переносимости . Конкретная реализация может определять, что происходит для определенного неопределенного поведения, и в некоторых случаях (особенно в драйверах устройств и небольших встроенных системах) вам необходимо использовать эти вещи.
Джерри Коффин
3
@Jerry: Нет, UB следует избегать, если он полностью не определен . Если платформа / реализация / среда выполнения / компилятор предоставляют дополнительные гарантии, вы можете положиться на поведение и потерять переносимость. Но тогда это уже не так undefined ... Однако в большинстве случаев у вас нет таких гарантий, а undefined просто undefined, и его следует избегать любой ценой.
jalf
«последовательный» может быть вводящим в заблуждение описанием неопределенного поведения. Оно должно соответствовать общему контексту операции, например, если выражение имеет «неопределенное значение», тогда результат должен быть значением, если вы его сохраняете, то сохраненное значение должно впоследствии сравниваться с самим собой, и так далее. Но неопределенные результаты не обязательно должны быть согласованными во времени (тот же вывод для того же ввода, если вы запустите его снова) или даже детерминированными.
Стив Джессоп
«больше не так неопределенно» - это точно так же, как не определено стандартом , а UB - это сокращенное значение, не определенное стандартом. В вашем примере это определяется реализацией. В этом отношении вы можете полагаться на поведение, которое не определено стандартом или реализацией, если вы проверили объектный код и не планируете повторно компилировать когда-либо снова ;-)
Стив Джессоп,
"должен после этого сравнивать себя равным". Хм, если только это NaN. В любом случае он должен иметь любое поведение, требуемое от его типа.
Стив Джессоп,
8
  • IB: поведение, определяемое реализацией - компилятор должен задокументировать, что он делает. >>Примером может служить выполнение операции с отрицательным значением.

  • UB: неопределенное поведение - компилятор может делать что угодно, в том числе просто давать сбой или давать непредсказуемые результаты. В эту категорию попадает разыменование нулевого указателя, но также и более тонкие вещи, такие как арифметика указателя, выходящая за пределы объекта массива.

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

Майкл Берр
источник
4

Краткая версия:

Поведение, определяемое реализацией (IB): правильно запрограммировано, но неопределенно *

Неопределенное поведение (UB): неправильно запрограммировано (т.е. ошибка !)

*) «неопределенный» в том, что касается языкового стандарта, он, конечно, будет определяться на любой фиксированной платформе.

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