﻿# 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:

```cpp
enum class byte : unsigned char {}; // Range: [0; 255]
byte b1 = static_cast<byte>(255);   // ok
```

Число 256 уже не вмещается в тип 'char', и этот код некорректен:

```cpp
byte b2 = static_cast<byte>(256);   // UB
```

Если не указан нижележащий тип, то, согласно стандарту, компилятор пытается уместить значения в зависимости от инициализатора в следующие типы:

```cpp
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:

```cpp
enum foo { a = 0, b = UINT_MAX }; // Range: [0; UINT_MAX]
foo x = foo(-1);                  // UB
```

На первый взгляд, такой код является корректным, но на самом деле он может приводить к проблемам\. Нижележащим типом 'enum' выбирается 'unsigned int'\. Число '\-1' не попадает в диапазон этого типа, поэтому такое присвоение может привести к неуточнённому или неопределённому поведению\.

Пример 3:

```cpp
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 оно уже не вмещается:

```cpp
EN a2 = static_cast<EN>(8);    // UB
```

UndefinedBehaviorSanitizer также находит ошибку в этом примере: [https://godbolt\.org/z/GGYo7z](https://godbolt.org/z/GGYo7z)\.

При этом, если для EN указать нижележащий тип, например 'unsigned char', то это уже будет [корректный вариант кода](https://godbolt.org/z/xjzT6d):

```cpp
enum EN : unsigned char { low = 2, high = 4 }; // Range: [0; 255]
EN a2 = static_cast<EN>(8);                    // ok
```