What is accidental macro substitution?
In Vera++ C++ linter, rule T016 states:
The calls to min and max functions should be protected against accidental macro substitution.
x = max(y, z); // wrong, vulnerable to accidental macro substitution x = (max)(y, z); // OK x = max BOOST_PREVENT_MACRO_SUBSTITUTION (y, z); // OK
Why is this a good rule, and what is so special about min and max functions that require this rule?
Macro substitution is a mechanism that provides a string substitution. It can be achieved through "#deifne". It is used to replace the first part with the second part of the macro definition, before the execution of the program. The first object may be a function type or an object.
In computer programming, a macro (short for "macro instruction"; from Greek μακρο- 'long, large') is a rule or pattern that specifies how a certain input should be mapped to a replacement output. Applying a macro to an input is known as macro expansion.
Macros can be used for abbreviation, abstraction, simplification, or structuring. Many application programs, such as word processors or spreadsheets, offer a macro language for writing scripts or subroutines that bundle a number of simpler actions into one command.
Accidental macro substitution is unintentional use of a macro whose name conflicts with a function.
The situation Vera++'s checks are designed to prevent occurs when misbehaved system headers — most famously <windows.h>
— define min
and max
macros that interfere with application-defined functions of the same name or even with standard library functions such as std::min<T>
, std::max<T>
, and std::numeric_limits<T>::min()
. (Other names have been known to cause clashes as well.)
Since macros are not namespace-aware, invoking the functions as std
::min(...)
doesn't help because min
is still expanded by the preprocessor. To work around this issue, such functions must be invoked as (function)(args...)
, which will prevent macroexpansion provided it is defined as #define function(arg1, arg2) ...
, as is typically the case with min
and max
. Another available option is to #undef
them before usage, but after including the misbehaving header. Boost provides its own substitution prevention marker, although its self-descriptiveness is offset by the clutter it introduces.
If you control inclusion of <windows.h>
, you can also #define NOMINMAX
prior to its inclusion, which will instruct windows.h
not to define the min
and max
macros.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With