V2652. MISRA. Argument of an integer constant macro should have an appropriate form.
This diagnostic rule is based on the MISRA (Motor Industry Software Reliability Association) software development guidelines.
This diagnostic rule is relevant only for C.
According to the C11 standard (Section 7.20.4), macro arguments for integer constants should meet the following requirements:
- They should be non-negative integer constants in decimal, octal, or hexadecimal notation.
- They should not contain suffixes, since the type and dimension are defined by the macro itself.
- Values should be within the valid range for the type corresponding to the width specified in the macro name. For example, the
INT8_C
value should be in the[-128 .. 127]
range.
Note. The argument should be an integer literal. It excludes any other expressions, even with a unary minus.
In addition, incorrect use of integer constant macros can lead to unexpected behavior.
The example:
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));
}
During the code compilation, the preprocessor converts the UINT32_C(16L)
macro call into a numeric 16LU
literal of the unsigned long
type. As a result, the generic selection expression chooses the unsigned long
association, and the do_something_ul
function is called. This behavior may be unexpected, as the intended result of the macro call is a literal of the unsigned int
type, and the function do_something_ui
is called.
The fixed code:
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));
}