Predefined tokens
__FILE__ // current source filename
__LINE__ // current line number
__DATE__ // compilation date "Mmm dd yyyy"
__TIME__ // compilation time "hh:mm:ss"
__STDC__ // 1 if the compiler conforms to ISO C
Simple textual substitution
#define forever for (;;)
#define CASE break; case
#define reg register
Multiline macro
#define printStars() \
for (int k = 0; k < 5; ++k) \
putchar('*');
int main(void)
{
printStars();
return 0;
}
Parameterized macros
#define SQR(x) ((x) * (x))
Parentheses are mandatory to avoid operator-precedence surprises:
SQR(3 + 1) // expands to ((3 + 1) * (3 + 1)) -> 16
Constructing new control-flow keywords
#define DO do
#define WHILE(x) while (x)
int main(void)
{
int i = 0;
DO {
puts("*");
++i;
} WHILE (i < 5);
return 0;
}
Macro expansion rules
- Scan the actual arguments list; if any argument is itself a macro, expand it first.
- Substitute the expanded arguments into the replacement list.
- Rescan the result; if new macro names appear, repeat the process.
Macros versus functions
| Aspect | Macro | Function |
|---|---|---|
| Overhead | Zero call/return cost | Call + return instructions |
| Type safety | None (textual replacement) | Full type checking |
| Code size | Grows with every use | Single definition |
| Side effects | Arguments re-evaluated per use | Evaluated once |
Example where a macro outperforms a functon:
#define ALLOC(T, n) ((T *)malloc((n) * sizeof(T)))
int *pi = ALLOC(int, 100);
Side-effect pitfalls
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int x = 5, y = 7;
int z = MAX(x++, y++); // x and y incremented twice
Undefining a macro
#undef MAX
Conditional compilation
#if defined(DEBUG)
#define LOG(msg) printf("DEBUG: %s\n", msg)
#elif LOGLEVEL >= 2
#define LOG(msg) printf("INFO: %s\n", msg)
#else
#define LOG(msg)
#endif
File inclusion
#include "config.h" // search user paths first
#include <stdio.h> // search system paths
The preprocessor replaces each #include directive with the entire content of the referenced file. If the same header is included by ten translation units, its processed ten times, but the compile-time cost is negligible and has no impact on runtime performance.