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

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

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

Все аргументы, передаваемые в [макросы](https://en.cppreference.com/w/c/numeric/tgmath.html) из заголовочного файла `<tgmath.h>`, должны иметь один из следующих типов: `essentially signed`, `essentially unsigned`, `essentially real floating`, `essentially complex floating`\. Эти типы предназначены для арифметических операций, в дальнейшем будем называть их арифметическими\.

Стандарт MISRA определяет собственную модель типов \([Essential type model](https://pvs-studio.ru/ru/blog/terms/7007/)\)\.

Использование аргументов `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>`\.

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

```cpp
#include <tgmath.h>

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

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

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

![V2649_ru/image1.png](https://import.viva64.com/docx/blog/V2649_ru/image1.png)

Исключения:

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

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

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

```cpp
#include <tgmath.h>

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