Окказионализм (филология)
- 1 year ago
- 0
- 0
Неуточнённое поведение ( англ. unspecified behavior ) и поведение, определяемое реализацией ( англ. implementation-defined behavior ) — поведение компьютерной программы , которое может различаться на разных платформах и компиляторах, поскольку спецификация языка программирования предлагает несколько допустимых вариантов реализации некой языковой конструкции. В отличие от неопределённого поведения , программа с неуточнённым поведением с точки зрения соответствия спецификации языка не считается ошибочной; при неуточняемом поведении, спецификация обычно ограничивает возможные варианты поведения, хотя и не сводит их в единое допустимое.
Разница между тем и другим такая: поведение, определяемое реализацией, задокументированное и последовательное на данном процессоре, программном окружении, версии системы и т. д. Неуточнённое поведение может меняться от случая к случаю, но система обязательно сделает что-то разумное — а не уйдёт в аварийный режим.
Программист должен избегать:
Согласно стандарту языка C99 ,
- 3.4.1. поведение, определяемое реализацией ( англ. implementation-defined behavior ) — неуточняемое поведение, где каждая реализация документирует выбор поведения;
- 3.4.3. неуточняемое поведение ( англ. unspecified behavior ) — использование неуточняемого значения или иное поведение, где данный Международный стандарт предоставляет два или более варианта и не налагает никаких других требований на выбор в каждом конкретном случае.
Оригинальный текст (англ.)3.4.1 implementation-defined behaviorunspecified 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— ISO/IEC 9899:201x
Согласно стандарту языка C++ ,
- 1.3.5. поведение, определяемое реализацией ( англ. implementation-defined behavior ) — поведение правильно построенной программной конструкции с правильными данными которое зависит от реализации и которое должно быть документировано каждой реализацией;
- 1.3.13. неуточняемое поведение ( англ. unspecified behavior ) — поведение правильно построенной программной конструкции с правильными данными которое зависит от реализации. Реализация не обязана документировать выбор поведения. [Примечание: как правило, диапазон допустимых поведений указан в данном Международном стандарте.]
Оригинальный текст (англ.)1.3.5 implementation-defined behaviorbehavior, 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», зависит от компилятора.
#include <iostream>
int f() {
std::cout << "F" << std::endl;
return 3;
}
int g() {
std::cout << "G" << std::endl;
return 4;
}
int h(int i, int j) {
return i + j;
}
int main() {
return h(f(), g());
}
Классическим примером поведения, определяемого реализацией (неуточняемого поведения, которое обязано быть документировано реализациями), является размер типов данных; например long в различных компиляторах и операционных системах может быть размером в 32 или 64 бит. Программа, которая предполагает, что в один long всегда поместится указатель , будет некорректно работать на некоторых платформах (например, в Windows x64 ) .
Вот две реализации быстрого обратного квадратного корня : реализация Кармака — Абраша ( Quake III ) и реализация на Си++20 из английской Википедии:
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
i = 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 removed
return y;
}
constexpr float Q_rsqrt(float number) noexcept
{
static_assert(std::numeric_limits<float>::is_iec559);
float const y = std::bit_cast<float>(
0x5f3759df - (std::bit_cast<std::uint32_t>(number) >> 1));
return y * (1.5f - (number * 0.5f * y * y));
}
Первая сделана для Windows и 32-битного Linux, вторая более универсальна: даёт ошибку компиляции, если на машине нестандартные дробные типы; не требует, чтобы long был 32-битным.