﻿# V2652\. MISRA\. Argument of an integer constant macro should have an appropriate form\.

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

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

Согласно пункту 7\.20\.4 стандарта [C11](https://open-std.org/JTC1/SC22/WG14/www/docs/n1570.pdf) аргументы [макросов для целочисленных констант](https://en.cppreference.com/w/c/types/integer.html#Function_macros_for_minimum-width_integer_constants) должны соответствовать следующим требованиям:

1. Должны быть неотрицательными [целочисленными константами](https://en.cppreference.com/w/c/language/integer_constant.html), записанными в десятичной, восьмеричной или шестнадцатеричной системах счисления\.
1. Не должны содержать суффиксов, так как тип и размерность определены самим макросом\.
1. Значения должны находиться в пределах допустимого диапазона для типа, соответствующего ширине, указанной в имени макроса\. Например, значение `INT8_C` должно находится в диапазоне `[-128 .. 127]`\.

Отметим отдельно, что аргумент должен быть именно целочисленным литералом\. Это исключает любые другие выражения, в том числе с унарным минусом\.

Кроме того, неправильное использование макросов для целочисленных констант может приводить к неожиданному поведению\.

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

```cpp
void do_something_ui(unsigned int value);
void do_something_ul(unsigned long value);
void do_something(unsigned long long);

#define DO_SOMETHING(X) Generic( (X)                             \
                                , unsigned int: do_something_ui  \
                                , unsigned long: do_something_ul \
                                , default: do_something ) (X)

int foo(void)
{
  DO_SOMETHING(UINT32_C(16L)); 
}
```

При компиляции этого кода препроцессор преобразует макровызов `UINT32_C(16L)` в числовой литерал `16LU`, имеющий тип `unsigned long`\. В результате выражение generic selection выберет ассоциацию `unsigned long`, и произойдёт вызов функции `do_something_ul`\. Такое поведение может быть неожиданным для разработчика, который рассчитывал на то, что результатом вызова макроса будет литерал типа `unsigned int` и предполагалось, что произойдёт вызов функции `do_something_ui`\.

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

```cpp
void do_something_ui(unsigned int value);
void do_something_ul(unsigned long value);
void do_something(unsigned long long);

#define DO_SOMETHING(X) Generic( (X)                             \
                                , unsigned int: do_something_ui  \
                                , unsigned long: do_something_ul \
                                , default: do_something ) (X)

int foo(void)
{
  DO_SOMETHING(UINT32_C(16)); 
}
```