V2650. MISRA. Controlling expression of generic selection should have essential type that matches its standard type
Диагностическое правило основано на руководстве MISRA (Motor Industry Software Reliability Association) по разработке программного обеспечения.
Правило актуально только для языка C.
Сущностный тип (essential type) управляющего выражения конструкции _Generic (C11) должен соответствовать стандартному типу.
Исключения составляют целочисленные константные выражения, имеющие essentially signed или essentially unsigned тип ниже ранга int и не относящиеся ни к символьным, ни к булевым константам.
Примечание:
- Константа перечисления (
enum) имеет типsigned int. Она не будет соответствовать ни определённому нижележащему типу, если он отличается отint, ни неразличимому типу перечисления. trueиfalse, определённые в<stdbool.h>и имеющие типint, не будут соответствовать ассоциации типа_Bool.
Код, который пишется в соответствие с руководящими принципами MISRA, должен также соответствовать системе типов Essential Type Model. Соответствие системе типов MISRA призвано помочь снизить количество дефектов в коде.
Сущностный тип ассоциации, выбранной через generic selection, должен соответствовать сущностному типу управляющего выражения. Если это не так, то код нарушает систему типов MISRA, что может свидетельствовать о наличии ошибок в коде.
Рассмотрим пример:
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.
Исправить это можно так:
static void CheckChar()
{
char c = 'c';
dispatcher(c);
}
Так как теперь в generic selection явно передаётся переменная типа char, будет выбрана правильная ассоциация. При этом сущностный тип контролирующего выражения (essentially character) будет соответствовать его стандартному типу char.
Не допускается использование перечисляемого типа в качестве управляющего выражения generic selection, который содержит базовый тип в списке ассоциаций. Ограничение применимо как к объектам перечисляемого типа, так и к константам перечисления.
Рассмотрим пример c enum:
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.
Данная диагностика классифицируется как:
|