# V2649. MISRA. All arguments of any type-generic macros from <tgmath.h> should have an appropriate essential type.

Диагностическое правило основано на руководстве MISRA (Motor Industry Software Reliability Association) по разработке программного обеспечения.

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

Все аргументы, передаваемые в макросы из заголовочного файла `<tgmath.h>`, должны иметь один из следующих типов: `essentially signed`, `essentially unsigned`, `essentially real floating`, `essentially complex floating`. Эти типы предназначены для арифметических операций, в дальнейшем будем называть их арифметическими.

Стандарт MISRA определяет собственную модель типов (Essential type model).

Использование аргументов `essentially complex floating` типа для следующих макросов может привести к неопределённому поведению:

`atan2`, `cbrt`, `ceil`, `copysign`, `erf`, `erfc`, `exp2`, `expm1`, `fdim`, `floor`, `fma`, `fmax`, `fmin`, `fmod`, `frexp`, `hypot`, `ilogb`, `ldexp`, `lgamma`, `llrint`, `llround`, `log10`, `log1p`, `log2`, `logb`, `lrint`, `lround`, `nearbyint`, `nextafter`, `nexttoward`, `remainder`, `remquo`, `rint`, `round`, `scalbn`, `scalbln`, `tgamma`, `trunc`

Примечание. Последний аргумент макросов `frexp` и `remquo` используется для записи результата, тип этого аргумента может отличаться от остальных.

Использование неарифметических типов в качестве аргументов может привести к неопределённому поведению, поскольку они не могут быть преобразованы к вещественным типам, которые используются в макросах из заголовочного файла `<tgmath.h>`.

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

    #include <tgmath.h>

    char sampleSqrt(char ch)
    {
      return sqrt(ch);
    }

Здесь в качестве аргумента макроса `sqrt` используется переменная типа `char`. В результате раскрытия макроса будет вызвана функция, принимающая аргумент типа `double`, а сам аргумент преобразован к типу `double`. Однако, согласно стандарту MISRA, `char` не является арифметическим типом и не предназначен для использования в вычислениях.

Преобразование между вещественными и символьными типами лишено смысла, поскольку нет точного соответствия между этими двумя представлениями. В итоге подобное преобразование может привести к неопределённому поведению. Стандарт MISRA определяет следующую таблицу преобразований типов и случаев, когда таких преобразований следует избегать:

Исключения:

- Переменная типа `enum` может быть приведена к синониму этого же типа.
- Переменные, имеющие константные значения `0` и `1`, могут быть приведены из целочисленного типа к `Boolean`.

В данном случае стоит использовать один из вещественных типов, например, `double`.

Исправленный пример:

    #include <tgmath.h>

    double sampleSqrt(double ch)
    {
      return sqrt(ch);
    }

Данная диагностика классифицируется как:

MISRA-C-2023-21.22