Что означает [Примечание] в параграфе неопределенного поведения в стандарте C++?

Как указывает Tony Delroy , в пункте 1.3.12 стандарта C++ есть [Примечание]

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

Разве это не противоречит определению UB о том, что ... этот международный стандарт не предъявляет никаких требований? Я имею в виду, что они говорят "нет требований", а затем говорят "допустимый UB" - прямо в том же пункте.

Как следует интерпретировать это примечание? Это действительно ограничивает UB в любом случае?

3 ответа

Решение

Из §6.5.1 части 3 Директив ISO/IEC:

Примечания и примеры, включенные в текст стандарта, должны использоваться только для предоставления дополнительной информации, предназначенной для содействия пониманию или использованию стандарта, и не должны содержать положений, которым необходимо соответствовать, чтобы иметь возможность требовать соблюдения стандарт.

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

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

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

Интересно отметить, что компилятор почти всегда должен что-то компилировать! Рассмотрим этот фрагмент кода:

void f() { 1 / 0; }

поведение переводчика при столкновении с этим не очень хорошо определено, но он не может просто делать все, что ему нравится! Фактически, если это компилятор, он все равно должен компилировать этот модуль компиляции. Это потому, что поведение программы, содержащей эту функцию, все еще может быть четко определено! Компилятор не может знать, вызвана ли функция. Фактически этот вопрос возник, когда функция была "main()", и контроль наверняка проходил через нулевое деление, и в результате компилятору не разрешалось отклонять даже эту программу. Причина в том, что программа по-прежнему правильно сформирована, и компилятор, отвечающий требованиям, должен принимать все правильно сформированные программы (и отклонять все неправильно сформированные программы и выдавать диагностическое сообщение об ошибке, если не указано иное).

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

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

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