Что такое неопределенное поведение в C++? Чем он отличается от неопределенного поведения?
В чем разница между неопределенным поведением и неопределенным поведением в C++? Является ли эта классификация действительной и для кодов C?
3 ответа
РЕДАКТИРОВАТЬ 1: последние проекты C11 и C++11 доступны онлайн здесь: C11 черновик N1570 и C++11 черновик n3242, если у вас нет копии окончательных стандартов и удивительно, как они выглядят. (Были внесены другие изменения в внешний вид текста и внесены некоторые изменения в формулировку / грамматику.)
РЕДАКТИРОВАТЬ 2: Исправлено все вхождения "поведение", чтобы быть "поведение", чтобы соответствовать стандарту.
При поиске стандартов C++11 и C11 не найдено совпадений для неопределенного правила или неопределенного правила. Существуют такие термины, как неопределенное значение, неопределенно упорядоченный, неопределенный неинициализированный и т. Д.
Если разговоры о ловушках и исключениях кажутся странными в ответе Нормана Грея, знайте, что эти термины отражают соответствующие определения в Разделе 3 стандарта C11.
C++ опирается на определения C. Многие полезные определения, касающиеся типов поведения, можно найти в Разделе 3 С11 (в С11). Например, неопределенное значение определено в 3.19.2. Обратите внимание, что Раздел 2 C11 (Нормативные ссылки) предоставляет другие источники для дополнительной интерпретации терминологии, а Раздел 4 определяет, когда такие случаи, как неопределенное поведение, происходят в результате несоблюдения стандарта.
Раздел 3.4 C11 определяет поведение, 3.4.1 определяет поведение, определяемое реализацией, 3.4.2 определяет поведение, зависящее от локали, 3.4.3 определяет неопределенное поведение, 3.4.4 определяет неопределенное поведение. Для значения (раздел 3.19) существуют значения, определенные реализацией, неопределенное значение и неопределенное значение.
Грубо говоря, термин " неопределенный" относится к неопределенному / неизвестному состоянию, которое само по себе не приводит к неопределенному поведению. Например, этот код C++ содержит неопределенное значение: { int x = x; }. (Это на самом деле пример в стандарте C++11.) Здесь x определяется как целое число сначала, но в этот момент у него нет четко определенного значения - затем он инициализируется любым (неопределенным / неизвестным) ценность это имеет!
Хорошо известный термин неопределенное поведение определен в 3.4.3 в C11 и относится к любой ситуации
непереносимая или ошибочная программная конструкция или ошибочные данные, для которых настоящий международный стандарт не предъявляет никаких требований
Другими словами, неопределенное поведение - это какая-то ошибка (в логике или состоянии), и что будет дальше, неизвестно! Таким образом, можно создать неопределенное правило [поведения], которое гласит: избегайте неопределенного поведения при написании кода на C/C++!:-)
Неопределенное правило [поведения] должно состоять в следующем: избегайте написания неопределенного кода, если он не нужен, и это не влияет на правильность или переносимость программы. Таким образом, в отличие от неопределенного поведения, неопределенное поведение не обязательно подразумевает, что код / данные являются ошибочными, однако, его последующее использование может быть или не быть ошибочным - поэтому необходимо соблюдать осторожность, чтобы гарантировать правильность программы.
Другие термины, например, неопределенно упорядоченные, содержатся в основном тексте (например, C11 5.1.2.3, пункт 3; C++11, раздел 1.9, пункт 13; т. Е. В [intro.executation]). (Как вы можете догадаться, это относится к неопределенному порядку действий.)
IMO, если кто-то заинтересован во всех этих нюансах, приобретение стандартов C++11 и C11 является обязательным. Это позволит исследовать до необходимого уровня детализации, необходимого с определениями и т. Д. Если у вас нет таких ссылок, приведенных здесь, это поможет вам изучить их с последним опубликованным проектом стандартов C11 и C++11.
Следующие замечания основаны на стандарте C, ISO-9899, а не на C++, но значения в основном одинаковы (см. Разделы 3.4 и 4 стандарта C; см. Также стандарт C++, ISO-14882, раздел 1.3. последний документ не определяет "неопределенное значение" как таковое, но использует эту фразу позже с очевидным значением). Официальные документы по стандартам не являются бесплатными (на самом деле, они дорогостоящие), но ссылки, приведенные выше, ведут на страницы комитетов и включают в себя бесплатные "черновики" стандарта, которые, как вы можете считать, по сути эквивалентны окончательному стандартному тексту.
Термины описывают лестницу неопределенности.
Итак, направляясь вниз....
В большинстве случаев стандарт определяет, что должно происходить в конкретном случае: если вы пишете c=a+b
а также a
а также b
являются int
, затем c
это их сумма (по модулю некоторых деталей). Это, конечно, точка стандарта.
Поведение, определяемое реализацией, - это когда стандарт перечисляет две или более вещи, которые могут произойти в конкретном случае; он не предписывает, какой из них предпочтительнее, но требует, чтобы реализация (фактический компилятор, который анализирует C) делал выбор между альтернативами, последовательно делал то же самое, и что реализация должна документировать свой выбор. Например, возможность открытия одного файла несколькими процессами определяется реализацией.
Неопределенное поведение - это когда стандарт перечисляет пару альтернатив, каждая из которых, следовательно, соответствует стандарту, но не идет дальше. Реализация должна выбрать одну из альтернатив, чтобы выбрать в конкретном случае, но не должна делать то же самое каждый раз, и не должна указывать в документации, какой выбор она сделает. Например, биты заполнения в struct
не определены.
Неопределенное поведение - самый крайний случай. Здесь все ставки сняты. Если компилятор или генерируемая им программа работает с неопределенным поведением, он может делать все что угодно: он может скремблировать память, повредить стек, HCF или, в стандартном крайнем случае, заставить демонов вылететь из носа. Но в основном это просто сбой. И все эти модели поведения соответствуют стандарту. Например, если переменная объявлена как static int i;
а также int i;
в том же объеме, или если вы пишете #include <'my file'.h>
, эффект не определен.
Есть аналогичные определения для "стоимости".
Неуказанное значение является допустимым значением, но стандарт не указывает, что это такое. Таким образом, стандарт может сказать, что данная функция возвращает неопределенное значение. Вы можете сохранить это значение и просмотреть его, если хотите, не вызывая ошибки, но это ничего не значит, и в следующий раз функция может вернуть другое значение, в зависимости от фазы луны.
Значение, определяемое реализацией, похоже на поведение, определяемое реализацией. Как и неопределенное, это допустимое значение, но документация реализации должна фиксировать то, что будет возвращено, и каждый раз делать одно и то же.
Неопределенное значение даже больше не указано, чем не указано. Это либо неопределенное значение, либо представление ловушки. Представление ловушки является стандартом для некоторой магической ценности, которая, если вы попытаетесь присвоить ее чему-либо, приведет к неопределенному поведению. Это не должно быть фактическим значением; вероятно, лучший способ думать об этом - "если бы в C были исключения, то представление ловушек было бы исключением". Например, если вы объявите int i;
в блоке, без инициализации, начальное значение переменной i
является неопределенным, что означает, что если вы попытаетесь присвоить это чему-то другому до его инициализации, поведение будет неопределенным, и компилятор имеет право попробовать указанный трюк с демонами из носа. Конечно, в большинстве случаев компилятор делает что-то менее драматичное / забавное, например, инициализирует его значением 0 или другим случайным допустимым значением, но независимо от того, что он делает, вы не имеете права возражать.
Смысл всей этой неточности в том, чтобы дать максимальную свободу авторам компилятора. Это хорошо для авторов компиляторов (и это одна из причин, по которой довольно легко запустить компилятор C на таком огромном спектре платформ), но это делает вещи более интересными, чем увлекательными для бедных пользователей.
Редактировать 1: уточнить неопределенные значения.
Изменить 2: включить ссылку на стандарт C++ и отметить, что проекты комитетов по существу эквивалентны окончательному стандарту, но бесплатны.
Я думаю, что стандарт упоминает неопределенное поведение и неопределенное значение. Итак, один о поведении, а другой о ценностях.
Эти два являются несколько ортогональными, например, поведение все еще может быть хорошо определено при наличии неопределенных значений.