Macros are dangerous because their use resembles that of real functions, but they have different semantics. The inline function-specifier was introduced to the C programming language in the C99 standard. Inline functions should be preferred over macros when they can be used interchangeably. Making a function an inline function suggests that calls to the function be as fast as possible by using, for example, an alternative to the usual function call mechanism, such as inline substitution. (See also PRE31-C. Do not perform Avoid side effects in arguments to unsafe macros, PRE01-C. Use parentheses within macros around parameter names, and PRE02-C. Macro replacement lists should be parenthesized.)
...
Code Block | ||||
---|---|---|---|---|
| ||||
#define CUBE(X) ((X) * (X) * (X)) /* ... */ void func(void) { int i = 2; int a = 81 / CUBE(++i); /* ... */ } |
For this example, the initialization for a
expands to
Code Block | |
---|---|
bgColor | #FFCCCC | lang | c
int a = 81 / ((++i) * (++i) * (++i));
|
which is undefined. (See EXP30-C. Do not depend on the order of evaluation for side effects.)
Compliant Solution
When the macro definition is replaced by an inline function, the side effect is executed only once before the function is called:
Code Block | ||||
---|---|---|---|---|
| ||||
inline int cube(int i) { return i * i * i; } /* ... */ void func(void) { int i = 2; int a = 81 / cube(++i); /* ... */ } |
Noncompliant Code Example
...
Code Block | ||||
---|---|---|---|---|
| ||||
int operations = 0, calls_to_F = 0, calls_to_G = 0; #define F(x) (++operations, ++calls_to_F, 2 * x) #define G(x) (++operations, ++calls_to_G, x + 1) /* ... */ void func(int x) { int y = F(x) + G(x); } |
The variable operations
is both read and modified twice in the same expression, so it can receive the wrong value if, for example, the following ordering occurs:
...
This noncompliant code example also violates EXP30-C. Do not depend on the order of evaluation for side effects.
Compliant Solution
The execution of functions, including inline functions, cannot be interleaved, so problematic orderings are not possible:
Code Block | ||||
---|---|---|---|---|
| ||||
int operations = 0, calls_to_F = 0, calls_to_G = 0; inline int f(int x) { ++operations; ++calls_to_fF; return 2 * x; } inline int g(int x) { ++operations; ++calls_to_gG; return x + 1; } /* ... */ void func(int x) { int y = f(x) + g(x); } |
Platform-Specific Details
...