V1016. The value is out of range of enum values. This causes unspecified or undefined behavior.
Анализатор обнаружил опасное приведение числа к перечислению. Указанное число может не входить в диапазон значений 'enum'.
Примечание 1: Данное правило актуально только для языка C++. В качестве нижележащего типа 'enum' в языке C всегда используется тип 'int'.
Примечание 2: Данное правило актуально только для C++ компиляторов, рассчитывающих фактический размер 'enum' согласно стандарту. Например, такими компиляторами являются GCC и Clang. MSVC не является таким компилятором, так как рассчитывает размер 'enum' в целях обратной совместимости по правилам языка C и в качестве нижележащего типа всегда использует тип 'int', если специально не указан иной тип.
Результат приведения числа, чьё значение не входит в диапазон элементов 'enum', является неуточненным поведением до C++17 и неопределенным поведением, начиная с C++17.
Если у 'enum' указан нижележащий тип, то к типу этого 'enum' можно приводить все значения, которые можно уместить в этот тип.
Пример 1:
enum class byte : unsigned char {}; // Range: [0; 255]
byte b1 = static_cast<byte>(255); // ok
Число 256 уже не вмещается в тип 'char', и этот код некорректен:
byte b2 = static_cast<byte>(256); // UB
Если не указан нижележащий тип, то, согласно стандарту, компилятор пытается уместить значения в зависимости от инициализатора в следующие типы:
int -> unsigned int -> long -> unsigned long ->
long long -> unsigned long long
При этом внутри выбранного типа компилятор использует минимально необходимое число бит (n), способное уместить максимальное число в перечислении. В такой 'enum' можно уместить диапазон значений [- (2^n) / 2; 2^n / 2 - 1] для 'enum' со знаковым нижележащим типом и [0; 2^n - 1] для 'enum' с беззнаковым нижележащим типом. Выход за границы этого диапазона является неуточненным поведением (до C++17) или неопределенным поведением (с C++17).
Пример 2:
enum foo { a = 0, b = UINT_MAX }; // Range: [0; UINT_MAX]
foo x = foo(-1); // UB
На первый взгляд, такой код является корректным, но на самом деле он может приводить к проблемам. Нижележащим типом 'enum' выбирается 'unsigned int'. Число '-1' не попадает в диапазон этого типа, поэтому такое присвоение может привести к неуточнённому или неопределённому поведению.
Пример 3:
enum EN { low = 2, high = 4 }; // Uses 3 bits, range: [0; 7]
EN a1 = static_cast<EN>(7); // ok
Согласно стандарту нижележащим типом для этого enum выберется 'int'. Внутри этого типа компилятор использует минимальное количество битовых полей, которое сможет вместить в себя все значения enum-констант.
В данном случае для вмещения всех значений (2 = 0b010 и 4 = 0b100) понадобится минимум 3 бита, поэтому переменная типа EN может вместить в себя числа от 0 (0b000) до 7 (0b111) включительно. Число 8 занимает уже четыре бита (0b1000), поэтому в тип EN оно уже не вмещается:
EN a2 = static_cast<EN>(8); // UB
UndefinedBehaviorSanitizer также находит ошибку в этом примере: https://godbolt.org/z/GGYo7z.
При этом, если для EN указать нижележащий тип, например 'unsigned char', то это уже будет корректный вариант кода:
enum EN : unsigned char { low = 2, high = 4 }; // Range: [0; 255]
EN a2 = static_cast<EN>(8); // ok
Данная диагностика классифицируется как:
|