Смекни!
smekni.com

Мобильное программирование в среде ОС UNIX (стр. 3 из 5)

Неопределенное поведение

Поведение не определяется для следующих ситуаций:

  • В исходной программе обнаружен символ, не входящий в требуемый набор. Исключение делается для препроцессорных лексем, символьных и строковых констант, а также примечаний.
  • Делается попытка модифицировать строковую константу.
  • Идентификаторы, которые должны обозначать одну и ту же сущность, различаются хотя бы одним символом.
  • В символьной или строковой константе обнаружена неизвестная управляющая последовательность.
  • Лексически первое описание функции или объекта данных с внешней связью не имеет файловой области видимости, а последующее описание лексически идентичного идентификатора имеет либо внутреннюю, либо внешнюю связь, что противоречит первому описанию.
  • Арифметическое преобразование дает результат, который не может быть представлен в отведенном пространстве.
  • Арифметическая операция неверна (например, деление на 0) или выдает результат, который нельзя представить в отведенном пространстве (например, переполнение или потеря значимости).
  • Число фактических параметров вызова не согласуется с числом формальных параметров функции, которая не имеет действующего в данной области видимости прототипа.
  • Типы фактических параметров вызова после расширения не согласуются с расширенными типами формальных параметров функции, которая не имеет действующего в данной области видимости прототипа и не имеет прототипа, действующего в области видимости, соответствующей области определения функции.
  • Прототип функции имеется в области видимости, соответствующей области определения функции, формальный параметр описан с типом, который изменяется в результате действия расширений типа, проводимых по умолчанию, а функция вызывается, когда в области видимости нет семантически эквивалентного прототипа.
  • Вызывается функция, обрабатывающая переменное число параметров, но прототип с эллиптической нотацией отсутствует в данной области видимости.
  • Вызывается функция с прототипом, видимым в данной области, ее формальный параметр описан с типом, который изменяется в результате действия расширений типа, проводимых по умолчанию, но в области определения функции не видно семантически эквивалентного прототипа функции.
  • Встретилась неверная ссылка на массив, ссылка на пустой указатель или ссылка на объект, размещенный в области автоматически распределяемой памяти завершившегося блока.
  • Указатель на функцию преобразуется в указатель на функцию другого типа и используется для вызова функции, тип которой отличается от первоначального.
  • Указатель на объект, не являющийся элементом массива, используется в операции прибавления или вычитания константы.
  • Вычисляется разность указателей, относящихся к разным массивам.
  • Результат выражения сдвигается на отрицательную величину или на величину, большую или равную (в битах) размеру сдвигаемого результата.
  • Сравниваются указатели, относящиеся к разным составным объектам.
  • Значение объекта присваивается перекрывающемуся по памяти объекту.
  • Делается попытка изменить объект, описанный как константа, с помощью указателя на тип, в котором нет атрибута const.
  • Объект, описанный с атрибутом volatile, указывается с помощью указателя на тип, не имеющего такого же атрибута.
  • Описания объекта, имеющего внешнюю связь, в двух разных файлах или в разных областях видимости одного файла, дают этому объекту разные типы.
  • Значение автоматического неинициированного объекта используется до первого присваивания.
  • Используется результат работы функции, которая, однако, не возвращает никакого значения.
  • Функция, обрабатывающая переменное число параметров, определяется без списка типов параметров в эллиптической нотации.
  • Фактический параметр макровызова не имеет ни одной препроцессорной лексемы.
  • Внутри списка параметров макровызова имеются препроцессорные лексемы, которые могут быть проинтерпретированы как директивы препроцессора.
  • В результате выполнения препроцессорной операции слияния лексем (##) получается неверная препроцессорная лексема.
  • Эффект, возникающий в программе при переопределении зарезервированного внешнего идентификатора.
  • Параметр identifier в макровызове offset соответствует битовому полю записи.
  • Фактический параметр библиотечной функции имеет неверное значение, если только поведение этой функции в подобном случае не описано явно.
  • Библиотечная функция, обрабатывающая переменное число параметров, не описана.
  • Для доступа к настоящей функции assert использована макродиректива #undef.
  • Фактический параметр функции, обрабатывающей символы, выходит за область определения.
  • Вызов функции setjmp производится в ином контексте, нежели при сравнении с целочисленным выражением из констант в переключателе или в условном операторе.
  • Значение автоматического объекта, не имеющего атрибута volatile, изменилось между вызовами setjmp и longjmp.
  • Функция longjmp вызывается из динамически вложенной программы обработки сигнала.
  • Сигнал возникает не в результате работы функций abort или raise, а при обработке сигнала вызывается библиотечная функция, не являющаяся самой функцией signal, или со статическим объектом проделывается не присваивание ему значения статической переменной с атрибутом volatile типа sig_atomic_t.
  • Параметр parmN макроопределения va_start описывается в классе регистровой памяти.
  • При вызове макроимени va_arg очередного фактического параметра не оказалось.
  • Тип фактического параметра из списка параметров не согласуется с типом, указанным в макровызове va_arg.
  • Функция va_end вызывается без предварительного обращения к макровызову va_start.
  • Из функции с переменным числом параметров, список которых был проинициирован с помощью макровызова va_start, возврат производится до вызова va_end.
  • Формат в функциях fprintf и fscanf не соответствует списку фактических параметров.
  • В формате функций fprintf или fscanf обнаружена неверная спецификация преобразования.
  • Среди спецификаторов преобразования для спецификации, не входящей в список o, x, X, e, E, f, g и G встретился признак #.
  • Фактическим параметром функции fprintf, не соответствующим преобразованиям %s и %p, является составной объект или указатель на составной объект.
  • Отдельное преобразование в функции fprintf породило более 509 выходных символов.
  • Фактическим параметром преобразования %p функции fscanf является значение указателя, выданное при преобразовании %p функцией fprintf во время предыдущих запусков программы.
  • Результат преобразования, выполняемого функцией fscanf, не может быть представлен в объеме памяти, отведенной для него, или полученный объект имеет неподходящий тип.
  • Результат преобразования строки в число с помощью функций atof, atoi или atol не может быть представлен.
  • Фактический параметр функций free или realloc не совпадает с ранее полученными указателями, выработанными функциями calloc, malloc или realloс, или указывается объект, ранее уничтоженный вызовом функций free или realloc.
  • Ссылка на память, освобожденную функциями free или realloc.
  • При вызове из функции exit функция, зарегистрированная обращением к atexit, производит доступ к автоматическому объекту программы.
  • Результат целочисленных арифметических функций (abs, div, labs или ldiv) не может быть представлен.
  • Массив, в который идет запись копированием или конкатенацией, слишком мал.
  • Функции memcpy, strcpy или strncpy копируют объект в перекрывающийся с ним по памяти другой объект.
  • В формате функции strftime обнаружена неверная спецификация преобразования.

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

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

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

Поведение, зависящее от реализации

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

Семантика фактических параметров функции main.

Для облегчения переноса программы полезно локализовать обработку внешних аргументов.

Число значащих начальных символов (сверх 31) в идентификаторе без внешней связи.

В переносимой программе не используется свыше 31 значащего символа в идентификаторах без внешней связи.

Число значащих начальных символов (сверх 6) в идентификаторе с внешней связью.

В переносимой программе не используется свыше 6 значащих символов в идентификаторах с внешней связью.

Имеет ли значение регистр символов, входящих в идентификаторы с внешней связью.