Неопределённое поведениеНеопределённое поведение (англ. undefined behavior, в ряде источников непредсказуемое поведение[1][2]) — ситуация, когда в определённых маргинальных случаях поведение программного продукта или устройства может меняться неконтролируемым образом и приводить к некорректным результатам, но это не является ошибкой, и о такой возможности указано в спецификации. Как правило, предполагается, что пользователь данного продукта имеет достаточную компетенцию, чтобы избежать этих случаев. Чаще всего речь идёт о неопределённом поведении в языках программирования. Неопределенное поведение не следует путать с неуточняемым поведением (unspecified behavior), при котором спецификация разрешает не любое поведение, а только ограниченный диапазон вариантов реализации. ПричиныОсновные причины, по которым может допускаться неопределённое поведение:
В качестве примера можно привести арифметические операции с переполнением. Например, необходимо вычислить в целых числах значение При небольших значениях a и b пример всегда решается корректно. Но если превысит максимальный для данной платформы результат, возникнет неопределённость:
Кроме того, неопределённое поведение может случиться и в другом месте, даже до сложения с переполнением. Оптимизирующий компилятор, исходя из знания об ограничениях платформы, может сделать вывод о максимально возможных значениях переменных, и выполнить оптимизации, которые могут работать некорректно при выходе этих переменных за данный диапазон — и неопределённое поведение может появиться вне выражения, собственно это неопределённое поведение вызвавшего. Например, если известно, что переменная a всегда больше 24 576, компилятор может посчитать, что переменная b всегда меньше 8192. Если при этом в коде где-то есть проверка, больше ли b чем 8192, которая при этом не меняет переменных a и b и не влияет на вычисление выражения, компилятор может посчитать, что её результат всегда будет равен true, и исключить её, даже если эта проверка осуществляется до исполнения выражения, вызывающего переполнение. Распространено жаргонное название последствий неопределённого поведения в C, как «носовых демонов», после того, как один из пользователей usenet объяснил UB как «если программа, содержащая UB, заставит демонов вылетать из вашего носа, это не будет нарушением спецификации»[3]. Борьба с неопределённым поведениемВ случае языков программирования и программных библиотек, борьба с неопределённым поведением возложена на плечи программиста, их использующего. Часть проблем можно обнаружить, используя статический анализ кода, некоторые проблемы проявляются в предупреждениях компилятора. В каких-то случаях приходится дополнять программу проверками на значения, которые могут вызвать UB. Некоторые языки программирования исключают неопределённое поведение, запрещая делать оптимизации, которые могли бы привести к UB и устанавливая дополнительные проверки выхода за границы. Также многие оптимизирующие компиляторы позволяют либо отключить подобные оптимизации, либо установить на опасные участки дополнительные проверки. ПримерыВ языке Си, к примеру, использование переменной до её инициализации приводит к неопределённому поведению. Согласно спецификации компилятор должен в этом случае сделать что-либо, что может показаться наиболее эффективным/простым. Неопределённое поведение возникает при попытке обращения к переменной. Библиотеки могут не проверять указатели на NULL для быстродействия. В процессорах x86, если есть два последовательных порта ввода-вывода и требуется записать информацию сначала в один порт, затем в другой — это следует делать по одному байту, поскольку порядок прихода байтов на оборудование не гарантируется. Ещё один пример неопределенного поведения: курьёз с ANSI-директивой «#pragma». Согласно спецификации языка, компиляторам предоставлена полная свобода при обработке этой конструкции. До версии 1.17 компилятор GCC при нахождении в исходном коде этой директивы пытался запустить Emacs с игрой «Ханойские башни».[4] В качестве ещё одного примера неопределённого поведения можно привести код: int i = 5;
i = ++i + ++i;
При его выполнении переменная Достоинства
Недостатки
Примечания
Ссылки
|
Portal di Ensiklopedia Dunia