﻿# V2650\. MISRA\. Controlling expression of generic selection should have essential type that matches its standard type

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

Правило актуально только для языка C\.

Сущностный тип \([essential type](https://pvs-studio.ru/ru/blog/terms/7007/)\) управляющего выражения конструкции [`_Generic`](https://en.cppreference.com/w/c/language/generic.html) \(C11\) должен соответствовать [стандартному типу](https://en.cppreference.com/w/c/language/types.html)\.

Исключения составляют [целочисленные константные выражения](https://en.cppreference.com/w/c/language/constant_expression.html#Integer_constant_expression), имеющие `essentially signed` или `essentially unsigned` тип ниже ранга `int` и не относящиеся ни к символьным, ни к булевым константам\.

**Примечание:**

* Константа перечисления \(`enum`\) имеет тип `signed int`\. Она не будет соответствовать ни определённому нижележащему типу, если он отличается от `int`, ни неразличимому типу перечисления\.
* `true` и `false`, определённые в `<stdbool.h>` и имеющие тип `int`, не будут соответствовать ассоциации типа `_Bool`\.

Код, который пишется в соответствие с руководящими принципами MISRA, должен также соответствовать системе типов [Essential Type Model](https://pvs-studio.ru/ru/blog/terms/7007/)\. Соответствие системе типов MISRA призвано помочь снизить количество дефектов в коде\.

Сущностный тип ассоциации, выбранной через generic selection, должен соответствовать сущностному типу управляющего выражения\. Если это не так, то код нарушает систему типов MISRA, что может свидетельствовать о наличии ошибок в коде\.

Рассмотрим пример:

```cpp
void handle_us(unsigned short input) {}
void handle_si(signed int input) {}
void handle_ui(unsigned int input) {}
void handle_ch(char ch) {}

#define dispatcher(X) (_Generic((X)                \
                      , unsigned short : handle_us \
                      , unsigned int   : handle_ui \
                      , char           : handle_ch \
                      , default        : handle_si) (X))


static void CheckChar()
{
  dispatcher('c');
}
```

В приведённом примере ожидалось, что для выражения `dispatcher('c')` будет выбрана функция `handle_ch(char)`\. Однако вместо этого произойдёт выбор функции из ветки по умолчанию — `handle_si(signed int)`\. Такое поведение обусловлено тем, что generic selection выбирает ассоциацию по стандартному типу контролирующего выражения\. Тип выражения `'c'` согласно стандарту языка C — `int`, поскольку это символьный литерал\. При этом сущностный тип этого выражения будет `essentially character`\.

Исправить это можно так:

```cpp
static void CheckChar()
{
  char c = 'c';
  dispatcher(c);
}
```

Так как теперь в generic selection явно передаётся переменная типа `char`, будет выбрана правильная ассоциация\. При этом сущностный тип контролирующего выражения \(`essentially character`\) будет соответствовать его стандартному типу `char`\.

Не допускается использование перечисляемого типа в качестве управляющего выражения generic selection, который содержит базовый тип в списке ассоциаций\. Ограничение применимо как к объектам перечисляемого типа, так и к константам перечисления\.

Рассмотрим пример c `enum`:

```cpp
static void CheckEnum()
{
  enum Mark { A, B, C, D };
  enum Mark tmp = A;
  dispatcher(tmp);
  dispatcher(A);
}
```



Оба выражения `dispatcher(tmp)` и `dispatcher(A)` нарушают описанное выше правило\.

Сущностный тип обоих выражений — `essentially enum`, а стандартные типы будут отличатся\. В соответствие со стандартом С, тип переменной `tmp` будет `unsigned int`, т\.к\. диапазон перечисления известен, и он не отрицательный, а тип константы перечисления `A` — `signed int`\.