Неуточнённое поведение (англ.unspecified behavior) и поведение, определяемое реализацией (англ.implementation-defined behavior) — поведение компьютерной программы, которое может различаться на разных платформах и компиляторах, поскольку спецификацияязыка программирования предлагает несколько допустимых вариантов реализации некой языковой конструкции. В отличие от неопределённого поведения, программа с неуточнённым поведением с точки зрения соответствия спецификации языка не считается ошибочной; при неуточняемом поведении, спецификация обычно ограничивает возможные варианты поведения, хотя и не сводит их в единое допустимое.
Разница между тем и другим такая: поведение, определяемое реализацией, задокументированное и последовательное на данном процессоре, программном окружении, версии системы и т. д. Неуточнённое поведение может меняться от случая к случаю, но система обязательно сделает что-то разумное — а не уйдёт в аварийный режим.
Неуточнённого поведения — там, где оно критично для результата программы. Пример: если две функции вызываются в неуточнённом порядке и в них общий отладочный код, это будет видно в отладочном журнале, но для результата может быть и не критично.
Но: если реализация уточняет неопределённое или неуточнённое поведение, программист может на неё закладываться. Примеры: хоть в Си переполнение знакового типа — это неопределённое поведение, на большинстве современных архитектур 32767+1=−32768. Если доступ по NULL-указателю обращается к вектору прерывания 0, или намеренно вызывает общую аварию программы, то это можно делать.
Поведения, определяемого реализацией — если в числе поддерживаемых платформ есть такие, что ведут себя по-разному. Пример: большинство 8- и 16-битных платформ (в основном микроконтроллеры и старые компьютеры) говорят, что целый тип int — это два байта, но если поддерживаем только сравнительно мощные машины, можно считать, что int — четыре байта.
3.4.1. поведение, определяемое реализацией (англ.implementation-defined behavior) — неуточняемое поведение, где каждая реализация документирует выбор поведения;
3.4.3. неуточняемое поведение (англ.unspecified behavior) — использование неуточняемого значения или иное поведение, где данный Международный стандарт предоставляет два или более варианта и не налагает никаких других требований на выбор в каждом конкретном случае.
Оригинальный текст (англ.)
3.4.1 implementation-defined behavior
unspecified behavior where each implementation documents how the choice is made
[…]
3.4.3 unspecified behavior
use of an unspecified value, or other behavior where this International Standard provides two or more possibilities and imposes no further requirements on which is chosen in any instance
1.3.5. поведение, определяемое реализацией (англ.implementation-defined behavior) — поведение правильно построенной программной конструкции с правильными данными которое зависит от реализации и которое должно быть документировано каждой реализацией;
1.3.13. неуточняемое поведение (англ.unspecified behavior) — поведение правильно построенной программной конструкции с правильными данными которое зависит от реализации. Реализация не обязана документировать выбор поведения. [Примечание: как правило, диапазон допустимых поведений указан в данном Международном стандарте.]
Оригинальный текст (англ.)
1.3.5 implementation-defined behavior
behavior, for a well-formed program construct and correct data, that depends on the implementation and
that each implementation shall document.
[…]
1.3.13 unspecifed behavior
behavior, for a well-formed program construct and correct data, that depends on the implementation. The
implementation is not required to document which behavior occurs. [Note: usually, the range of possible
behaviors is delineated by this International Standard. ]
— ISO/IEC 14882:2003(E)
Примеры
В Си и C++ (в отличие от языка Java) порядок вычисления параметров функции является неуточняемым; следовательно, в программе, указанной ниже, порядок, в котором будут напечатаны строки «F» и «G», зависит от компилятора.
Классическим примером поведения, определяемого реализацией (неуточняемого поведения, которое обязано быть документировано реализациями), является размер типов данных; например long в различных компиляторах и операционных системах может быть размером в 32 или 64 бит. Программа, которая предполагает, что в один long всегда поместится указатель, будет некорректно работать на некоторых платформах (например, в Windowsx64)[2].
floatQ_rsqrt(floatnumber){longi;floatx2,y;constfloatthreehalfs=1.5F;x2=number*0.5F;y=number;i=*(long*)&y;// evil floating point bit level hackingi=0x5f3759df-(i>>1);// what the fuck? y=*(float*)&i;y=y*(threehalfs-(x2*y*y));// 1st iteration// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removedreturny;}constexprfloatQ_rsqrt(floatnumber)noexcept{static_assert(std::numeric_limits<float>::is_iec559);floatconsty=std::bit_cast<float>(0x5f3759df-(std::bit_cast<std::uint32_t>(number)>>1));returny*(1.5f-(number*0.5f*y*y));}
Первая сделана для Windows и 32-битного Linux, вторая более универсальна: даёт ошибку компиляции, если на машине нестандартные дробные типы; не требует, чтобы long был 32-битным.