Function-like macro definition
ID |
objectivec.maintainability.avoid_function_like_macros |
Severity |
info |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Preprocessor |
Language |
Objective-C |
Description
Reports a #define whose name is immediately followed by a parameter list, that is, a function-like macro. An object-like macro such as #define TIMEOUT (30 * 1000), where a space separates the name from the parenthesis, is not reported.
Rationale
A function-like macro is expanded by the preprocessor as raw text, so it has no types, no scope and no single evaluation of its arguments. An argument with a side effect is evaluated once per textual occurrence, a missing pair of parentheses silently changes operator precedence at the call site, and a multi-statement body breaks when used as the body of an unbraced if. None of this is visible to the compiler’s type checker, to the debugger, or to a reader of the call site, which makes the resulting defects hard to find.
The following code illustrates the pattern detected by this rule:
// FLAGGED: Function-like macro definition
#define SQUARE(x) ((x) * (x))
Remediation
Replace the macro with a static inline C function or an Objective-C method, which gives the compiler real parameter types and evaluates each argument exactly once. Where a compile-time constant is all that is needed, use static const or an NS_ENUM. If a macro is genuinely unavoidable, parenthesize every parameter and the whole body, and use each parameter once.