Диагностическое правило основано на руководстве 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.
Данная диагностика классифицируется как:
|