6

Неопределенное, неуточненное и зависимое от реализации поведение

3

Каково определение неопределённого поведения (UB) в C и C++? Что можно сказать о неопределённом поведении и определённом реализацией поведении? Каково различие между этими концепциями?

5 ответ(ов)

0

В официальном документе C Rationale указано следующее:

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

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

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

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

0

На StackOverflow можно ответить следующим образом:

Определение на уровне реализации (Implementation defined):

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


Неопределённое значение (Unspecified):

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


Неопределённый (Undefined):

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

0

Исторически как Поведение, Определяемое Реализацией (Implementation-Defined Behavior), так и Неопределенное Поведение (Undefined Behavior) представляли собой ситуации, в которых авторы Стандарта ожидали, что разработчики качественных реализаций будут использовать собственное суждение для принятия решений о том, какие гарантию поведения, если таковые есть, будут полезны для программ в предполагаемой области применения и на целевых платформах. Потребности высокопроизводительного кода отличаются от потребностей низкоуровневого системного кода, и оба типа поведения (UB и IDB) предоставляют разработчикам компиляторов гибкость для удовлетворения этих различных потребностей. Ни одна из категорий не обязывает реализации вести себя таким образом, чтобы это было полезно для какой-либо конкретной цели или даже для какой-либо цели вообще. Однако качественные реализации, которые утверждают, что подходят для конкретной цели, должны вести себя подобающим образом независимо от того, требуется ли это Стандартом или нет.

Единственное различие между Поведением, Определяемым Реализацией, и Неопределенным Поведением заключается в том, что первое требует от реализаций определения и документирования согласованного поведения даже в случаях, когда ничего, что реализация могла бы сделать, не было бы полезным. Разделительная линия между ними не в том, полезно ли в общем случае реализациям определять поведение (разработчики компиляторов должны определять полезное поведение, когда это целесообразно, независимо от требований Стандарта), а в том, могут ли существовать реализации, в которых определение поведения одновременно будет затратным и бесполезным. Оценка того, что такие реализации могут существовать, никоим образом не подразумевает оценки полезности поддержки определенного поведения на других платформах.

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

Например, если рассмотреть следующий код:

int scaled_velocity(int v, unsigned char pow)
{
  if (v > 250)
    v = 250;
  if (v < -250)
    v = -250;
  return v << pow;
}

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

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

0

В C++ стандарт n3337 § 1.3.10 описывает определенное реализацией поведение:

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

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


В C++ стандарт n3337 § 1.3.24 описывает неопределенное поведение:

поведение, для которого этот Международный стандарт не накладывает никаких требований. [Примечание: Неопределенное поведение может ожидаться, когда этот Международный стандарт пропускает любое явное определение поведения или когда программа использует ошибочный конструктив или ошибочные данные. Допустимое неопределенное поведение варьируется от полного игнорирования ситуации с непредсказуемыми результатами до поведения во время трансляции или выполнения программы в документированном ключе, характерном для окружения (с или без выдачи диагностического сообщения), до завершения трансляции или выполнения (с выдачей диагностического сообщения). Многие ошибочные конструкции программы не приводят к неопределенному поведению; их требуется диагностировать. — конец примечания]

Когда программа сталкивается с конструкцией, которая не определена согласно стандарту C++, ей разрешается делать что угодно (например, отправить мне электронное письмо, вам электронное письмо или вовсе игнорировать код).


В C++ стандарт n3337 § 1.3.25 описывает неуточненное поведение:

поведение, для корректного конструкта программы и правильных данных, которое зависит от реализации. [Примечание: Реализация не обязана документировать, какое поведение происходит. Диапазон возможных поведений обычно определяется этим Международным стандартом. — конец примечания]

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

0

Неопределенное поведение — это страшная вещь, как в фильме "Добро, зло и дурное".

Хорошее: программа, которая компилируется и работает по правильным причинам.

Плохое: программа, содержащая ошибку, которую компилятор способен обнаружить и на которую может указать.

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

Некоторые языки программирования и другие формальные системы стараются ограничить "пропасть неопределенности" — то есть, они пытаются устроить так, чтобы большинство или все программы были либо "хорошими", либо "плохими", а очень немногое было "страшным". Однако для языка C характерно то, что его "пропасть неопределенности" достаточно широка.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь