﻿# V2591\. MISRA\. Bit fields should only be declared with explicitly signed or unsigned integer type\.

Диагностическое правило основано на руководстве [MISRA](https://www.misra.org.uk/) \(Motor Industry Software Reliability Association\) по разработке программного обеспечения\.

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

* **C90:** `signed int` или `unsigned int`\.
* **C99:** `signed int`, `unsigned int`, `_Bool` или другой интегральный тип, разрешённый имплементацией, с явным указанием модификатора `signed` или `unsigned`\.
* **C\+\+:** битовое поле должно иметь знаковый или беззнаковый нижележащий целочисленный тип при условии, что все его значения могут быть представлены в пределах ширины битового поля\. Также допустимо использование перечисления с фиксированным нижележащим типом, удовлетворяющим этому же условию\. 

Также разрешается использовать псевдоним \(`typedef`\) для допустимого нижележащего типа\.

Битовое поле типа `int` может быть как `signed`, так и `unsigned` в зависимости от компилятора\. Если для представления битового поля используется `unsigned int`, то все выделенные для поля биты будут значимыми\. Такое битовое поле из `n` битов имеет диапазон значений `[0, 2 ^ n - 1]`\.

Если же для представления битового поля используется `signed int`, то 1 бит будет выделен как знаковый\. Поэтому для записи значимой части значения битового поля будет использовано на 1 бит меньше выделенного\. Такое битовое поле из `n` битов имеет диапазон значений `[-2 ^ (n - 1), 2 ^ (n - 1) - 1]`\.

Исходя из этого, в зависимости от компилятора битовые поля типа `int` могут иметь разные диапазоны значений\. Чтобы избежать ошибок, которые могут возникнуть из\-за этого, нужно явно указывать модификатор знаковости\.

Пример неправильного использования битового поля:

```cpp
struct S
{
  int b : 3; // <=
};

void foo()
{
  S s;
  s.b = 5;
  if (s.b != 5)
  {
    Boom();
  }
}
```

Если компилятор выберет беззнаковый тип для представления битового поля `b`, тогда все 3 бита, в которые записывается значение 5, будут значимыми\. То есть фактически записывается остаток по модулю 8, и код будет работать как ожидается — в битовое поле будет записано значение 5\.

Если компилятор выберет знаковый тип для представления битового поля `b`, то оно разбивается на 1 бит знака и 2 бита значимой части\. При записи числа 5 в `b` в значимую часть запишутся только 2 младших бита\. В результате в битовое поле будет записано значение 1 вместо значения 5\. Поэтому проверка будет пройдена, и будет вызвана функция `Boom`\.

Для исправления нужно явно указывать модификатор знаковости \(`signed` / `unsigned`\):

```cpp
struct S
{
  unsigned int b : 3;
};

void foo()
{
  S s;
  s.b = 5;
  if (s.b != 5)
  {
    Boom();
  }
}
```

Для того, чтобы явно указать, какие типы допускаются в объявлении битовых полей вашим компилятором, поддерживающим стандарт C99, в файл с исходными кодом или pvsconfig\-файл можно добавить следующий комментарий:

```cpp
//V_2591_ALLOWED_C99_TYPES:short,long long
```

После двоеточия через запятую указываются допустимые типы без модификаторов знаковости:

* `char`;
* `short`;
* `long`;
* `long long`\.