В чем разница между "неопределенным поведением" и "поведением, определяемым реализацией", или почему даже различают их?

Стандарт C (AFAIK) использует оба термина. У меня проблемы с пониманием, где разница между ними.

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

Более конкретный пример: переполнение целочисленных значений. Теперь у нас есть два типа переполнения: арифметическое и по памяти. Если переполнение целых чисел со знаком является UB в соответствии со стандартом, что это значит? Может ли реализация просто пролить переполняющий бит в соседний байт к MSB? (Никогда не видел это, но будет ли это хорошо?)

Мне кажется, что "неопределенное поведение" всегда зависит от реализации. Или, другими словами, кажется, что компилятор не может обработать любое "неопределенное поведение" без введения поведения, определенного реализацией.

Так зачем даже различать два?

1 ответ

Основное отличие заключается в том, что поведение, определяемое реализацией, определено. То есть, для каждого требования в Стандарте, которое говорит "определяется реализацией", предполагается, что реализация C должна сопровождаться объяснением того, что такое поведение.

Например, вот документация GCC о поведении, определяемом реализацией для языка Си.

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

Читайте также блог Латтнера, что каждый программист должен знать о неопределенном поведении.

Другие вопросы по тегам