﻿# V1084\. The expression is always true/false\. The value is out of range of enum values\.

Анализатор обнаружил странное сравнение переменной перечисления с числом\. Указанное число не входит в диапазон значений перечисления, поэтому такое сравнение не имеет смысла\.

Если у перечисления указан нижележащий тип, то с переменной такого перечисления имеет смысл сравнивать только значения, которые можно уместить в этот тип\.

Рассмотрим следующий пример:

```cpp
enum byte : unsigned char {}; // Range: [0; 255]
void foo(byte b1)
{
  if (b1 == 256)   // logic error : always false
  {
    //....
  }
}
```

Перечисление 'byte' имеет нижележащий тип 'unsigned char'\. Число 256 не вмещается в тип 'unsigned char', поэтому сравнение 'b1 \=\= 256' всегда ложное\.

Пример корректного сравнения:

```cpp
enum byte : unsigned char {}; // Range: [0; 255]
void foo(byte b1)
{
  if (b1 == 255)   // ok
  {
    //....
  }
}
```

Более сложным случаем является перечисление без явного указания нижележащего типа\.

Для языка C компилятор всегда использует тип 'int' в качестве нижележащего типа\. Диапазоном значений перечисления будет весь диапазон 'int'\.

Для языка C\+\+ компилятор подставит в качестве нижележащего типа 'int' для строго типизированных перечислений \(scoped enum\)\. Диапазоном значений такого перечисления также будет весь диапазон 'int'\.

Для обычных перечислений вычисление диапазона значений и нижележащего типа перечисления происходит особым образом\. Согласно стандарту С\+\+, компилятор выведет нижележащий тип на основе значений констант перечисления, пытаясь уместить их в следующие типы:

```cpp
int -> unsigned int -> long -> unsigned long ->
 long long -> unsigned long long
```

При этом внутри выбранного типа компилятор использует минимально необходимое число бит \(n\), способное уместить весь диапазон констант в перечислении\. Такие перечисления смогут обрабатывать диапазон значений \[\- \(2 ^ n\) / 2; \(2 ^ n\) / 2 \- 1\] для знакового и \[0; \(2 ^ n\) \- 1\] для беззнакового нижележащего типа соответственно\. 

Поэтому следующий код на языке C\+\+ содержит ошибку, если используется компилятор, отличный от MSVC \(например, GCC или Clang\):

```cpp
enum EN { low = 2, high = 4 }; // Uses 3 bits, range: [0; 7]
void foo(EN en1)
{
  if (en1 != 8)   // logic error : always true
  {
    //....
  }
}
```

Согласно стандарту C\+\+, нижележащим типом для этого перечисления выберется 'int'\. Внутри этого типа компилятор использует минимальное количество битовых полей, которое сможет вместить в себя все значения enum\-констант\. 

В данном случае для вмещения всех значений \(2 \= 0b010 и 4 \= 0b100\) понадобится минимум 3 бита, поэтому переменная типа 'EN' может вместить в себя числа от 0 \(0b000\) до 7 \(0b111\) включительно\. Число 8 занимает уже четыре бита \(0b1000\), поэтому в тип 'EN' оно уже не вмещается\. Чтобы исправить ошибку, можно явно указать нижележащий тип:

```cpp
enum EN : int32_t { low = 2, high = 4 };
// Now range is: [−2 147 483 648, 2 147 483 647]
void foo(EN en1)
{
  if (en1 != 8)   // ok
  {
    //....
  }
}
```

Не все C\+\+ компиляторы рассчитывают фактический размер перечисления согласно стандарту\. Например, MSVC при компиляции C\+\+ кода отходит от стандарта и рассчитывает размер перечисления в целях обратной совместимости по правилам языка C\. Поэтому в качестве нижележащего типа MSVC всегда использует тип 'int', если специально не указан иной тип\. В таком случае диапазоном значений перечисления будет диапазон 'int'\. Поэтому в рассмотренном выше примере нет ошибки, если вы используете MSVC:

```cpp
enum EN { low = 2, high = 4 };
// MSVC will use int as underlying type
// range is: [−2 147 483 648, 2 147 483 647]

void foo(EN en1)
{
  if (en1 != 8)   // no logic error
  {
    //....
  }
}
```

Однако писать такой код не стоит, потому что он будет непереносим на другие компиляторы\. Следует явно указать 'int' в качестве нижележащего типа\.

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

```cpp
//-V1084_TURN_OFF_ON_MSVC
```

Предупреждения V1084, актуальные для MSVC, останутся\.