1. Basics of Macro Definition: The Essence of Text Replacement
A macro is one of the core functionalities of the C language preprocessing phase, and it is essentially text replacement, expanded by the preprocessor before compilation.
Basic Syntax
#define macro_name replacement_text
Example:
#define PI 3.1415926
#define MAX(a, b) ((a) > (b) ? (a) : (b))
Classic Macros in the Linux Kernel
#define likely(x) __builtin_expect(!!(x), 1) // Branch prediction optimization
#define unlikely(x) __builtin_expect(!!(x), 0)
2. Core Rules of Macro Expansion
Rule 1: Pure Text Replacement
A macro is merely string replacement, without type checking or computation:
#define SQUARE(x) x * x
int a = 3;
printf("%d\n", SQUARE(a + 1)); // After replacement: a + 1 * a + 1 → 3 + 1 * 3 + 1 = 7 (unexpected 16)
✅ Correct Usage:
#define SQUARE(x) ((x) * (x)) // Adding parentheses to ensure order of operations
Rule 2: Delayed Expansion of Macro Parameters
Macro parameters are not evaluated immediately during replacement, but are replaced first and then computed:
#define DOUBLE(x) x + x
int a = 5;
printf("%d\n", DOUBLE(a++)); // After replacement: a++ + a++ → 5 + 6 = 11 (and a becomes 7)
⚠️ Side Effect Warning: Avoid using macro parameters with <span>++</span>, <span>--</span>, and other operations that may be evaluated multiple times.
3. Special Macro Techniques
(1) Stringification (#)
Using <span>#</span> to convert macro parameters to strings:
#define STR(s) #s
printf("%s\n", STR(hello)); // Outputs "hello"
(2) Concatenation (##)
Using <span>##</span> to concatenate identifiers:
#define CONCAT(a, b) a##b
int xy = 100;
printf("%d\n", CONCAT(x, y)); // Outputs the value of xy: 100
(3) Variadic Macros (__VA_ARGS__)
Macros that support variable arguments:
#define LOG(fmt, ...) printf("[LOG] " fmt, ##__VA_ARGS__)
LOG("value=%d\n", 42); // Outputs: [LOG] value=42
4. Advanced Macro Applications in the Linux Kernel
(1) <span>container_of</span> Macro
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) *__mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); \
})
Function: Finds the address of the entire structure from a pointer to a structure member (widely used in linked lists and device drivers).
(2) <span>BUILD_BUG_ON</span> Compile-time Assertion
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
Function: If the condition is true, a compile-time error occurs (array size becomes negative).
5. Macros vs Inline Functions
| Feature | Macro | Inline Function |
|---|---|---|
| Processing Stage | Preprocessing (text replacement) | Compilation (generating machine code) |
| Type Safety | ❌ No type checking | ✅ Type checking present |
| Debugging | ❌ Difficult to debug (code after replacement) | ✅ Can be debugged normally |
| Use Case | Simple replacements, code generation | Complex logic, performance optimization |
Linux Kernel Preference:✅ Use macros for high-frequency small operations (like <span>likely/unlikely</span>)✅ Use <span>static inline</span> functions for complex logic
6. Pitfalls and Best Practices of Macros
Common Pitfalls
- Operator Precedence Issues (missing parentheses leading to errors)
- Multiple Evaluations of Parameters (e.g.,
<span>MAX(a++, b++)</span>) - Macro Name Conflicts (avoid using names starting with
<span>_</span>, which may conflict with system macros)
Best Practices
- Macro Names in Uppercase (e.g.,
<span>MAX_LEN</span>) - Add Parentheses to Parameters and Overall (e.g.,
<span>#define MUL(a, b) ((a) * (b))</span>) - Use
<span>inline</span>functions for complex logic
Conclusion
- Macros are text replacements in the preprocessing phase, flexible but prone to errors.
<span>#</span>and<span>##</span>achieve stringification and concatenation.- The Linux kernel extensively uses macros for optimization (like
<span>container_of</span><span>).</span> - Prefer inline functions, using macros only for simple replacements or special cases.
Question: What is the output of the following macro?
#define M(x, y) x##y
int ab = 100;
printf("%d", M(a, b));
(Answer: Outputs the value of <span>ab</span>, which is <span>100</span>)