V2646. MISRA. All arguments of any multi-argument type-generic macros from <tgmath.h> should have the same type.
This diagnostic rule is based on the MISRA (Motor Industry Software Reliability Association) software development guidelines.
This diagnostic rule is relevant only for C.
All arguments passed to macros from the <tgmath.h>
header file should be of the same type. Integer arguments should also be of the same type after integer promotion.
The rule applies to the following macros: atan2
, copysign
, fdim
, fma
, fmax
, fmin
, fmod
, frexp
, hypot
, ldexp
, nextafter
, nexttoward
, pow
, remainder
, remquo
, scalbn
, and scalbln
.
Note. The last argument of the frexp
and remquo
macros is for output. Its type may differ from the rest.
The called function and the return type are selected based on the argument types. The C language does not provide function overloading. However, you can select a suitable alternative when calling the corresponding macro in a specific compiler. For example, MSVC CL uses the generic selection mechanism for this purpose. If the argument types differ, the compiler may choose the wrong function, resulting in unexpected or inaccurate results.
The example:
#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
}
In this case, the macro arguments differ in size. As a result, different functions will be called: float powf(float, float)
in the first case, and double pow(double, double)
in the second. The logic for selecting a specific function depends on the compiler and is not always straightforward. In the second example, the result will be implicitly converted double
to float
. In some cases, such conversions may result in a loss of precision or slightly different evaluation results.
To avoid these errors, explicitly cast the arguments to the same type. This ensures that, after macro expansion, the correct function is called, the return value is a float
, and the results remain consistent.
The fixed example:
#include <tgmath.h>
void second()
{
double op1 = 15.61;
float op2 = 31.4;
float res = pow((float)op1, op2); //2.970643e+37
}
This diagnostic is classified as:
|