An unsafe function-like macro is one that, when expanded, evaluates its argument more than once or doesn't evaluate does not evaluate it at all. Contrasted with function calls, which always evaluate each of their arguments exactly once, unsafe function-like macros often have unexpected and surprising effects and lead to subtle, hard-to-find defects. (See rule PRE31-C. Avoid side-effects in arguments to unsafe macros.) Consequently, every function-like macro should evaluate each of its arguments exactly once. Alternatively and preferably, defining function-like macros should be avoided in favor of inline functions. (See recommendation PRE00-C. Prefer inline or static functions to function-like macros.)
...
Code Block | ||||
---|---|---|---|---|
| ||||
#define ABS(x) (((x) < 0) ? -(x) : (x))
void f(int n) {
int m;
m = ABS(++n); /* undefined behavior */
/* ... */
}
|
The invocation of the ABS()
macro in this noncompliant code example expands to the code belowfollowing code. Since the resulting expression modifies an object more than once, its behavior is undefined. (See rule EXP30-C. Do not depend on order of evaluation between sequence points.)
Code Block | ||||
---|---|---|---|---|
| ||||
m = (((++n) < 0) ? -(++n) : (++n)); /* undefined behavior */
|
...
Code Block | ||||
---|---|---|---|---|
| ||||
inline int Abs(x) {
return x < 0 ? -x : x;
}
|
...
Some implementations provide language extensions that make it possible to define safe function-like macros, such as the macro ABS()
above , that would otherwise require evaluating their arguments more than once. For example, the gcc the GCC extension Statements and Declarations in Expressions makes it possible to implement the macro ABS()
in a safe way. Note, however, that since relying on implementation-defined extensions introduces undesirable platform dependencies that may make the resulting code non-portablenonportable, such solutions should be avoided in favor of portable ones wherever possible. (See recommendation MSC14-C. Do not introduce unnecessary platform dependencies.)
Code Block | ||||
---|---|---|---|---|
| ||||
#define ABS(x) ({int tmp = (x); tmp < 0 ? -tmp : tmp; })
|
...
Defining an unsafe macro leads to invocations of the macro with an argument that has side effects, causing those side effects to occur more than once. This can lead to unexpected or undefined program behavior.
...
CERT C++ Secure Coding Standard: PRE12-CPP. Do not define unsafe macros
ISO/IEC 9899:19992011 Section 5.1.2.3, "Program execution"
...