﻿# V2646\. MISRA\. All arguments of any multi\-argument type\-generic macros from <tgmath\.h\> should have the same type\.

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

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

Все аргументы, передаваемые в [макросы](https://en.cppreference.com/w/c/numeric/tgmath.html) из заголовочного файла `<tgmath.h>`, должны иметь одинаковый тип\. Целочисленные аргументы после преобразования \([integer promotion](https://en.cppreference.com/w/c/language/conversion.html#Integer_promotions)\) также должны быть одного типа\.

Правило применимо к следующим макросам: `atan2`, `copysign`, `fdim`, `fma`, `fmax`, `fmin`, `fmod`, `frexp`, `hypot`, `ldexp`, `nextafter`, `nexttoward`, `pow`, `remainder`, `remquo`, `scalbn`, `scalbln`\.

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

На основе типов аргументов выбирается вызываемая функция и, соответственно, тип возвращаемого значения\. В C нет механизма перегрузки функций, однако выбор подходящей альтернативы при вызове соответствующего макроса всё же может быть реализован в конкретном компиляторе\. Например, в MSVC CL для этого используется механизм [generic selection](https://en.cppreference.com/w/c/language/generic.html)\. Если аргументы имеют разные типы, может быть выбрана неправильная функция, что, в свою очередь, может привести к непредсказуемому или неточному результату\.

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

```cpp
#include <tgmath.h>

void first()
{
  float op1 = 15.61;
  float op2 = 31.4;
  float res = pow(op1, op2); //2.970643e+37
}

void second()
{
  double op1 = 15.61;
  float op2 = 31.4;
  float res = pow(op1, op2); //2.970645e+37
}
```



В приведённом коде аргументы макроса имеют типы разных размеров\. В результате будут вызваны разные функции: `float powf(float, float)` в первом случае и `double pow(double, double)` — во втором\. Логика выбора конкретной функции зависит от компилятора и не всегда прозрачна\. К тому же, результат вычислений во втором примере будет неявно преобразован из типа `double` к типу `float`\. Подобные преобразования в некоторых случаях могут привести к потере точности или немного разным результатам вычислений\.

Избавиться от ошибки можно явно приведя аргументы к одинаковому типу\. В таком случае после раскрытия макроса будет вызвана соответствующая функция и возвращаемое значение гарантированно будет иметь тип `float`, а результаты не будут отличаться\.

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

```cpp
#include <tgmath.h>
 
void second()
{
  double op1 = 15.61;
  float op2 = 31.4;
  float res = pow((float)op1, op2); //2.970643e+37
}
```