Topic 11 of 15 · Advanced
Preprocessor & Macros
#define, macros, include guards and conditional compilation.
Concept
The preprocessor runs before compilation and does text substitution. #define creates constants and macros.
Function-like macros don't check types and can evaluate arguments twice — always wrap parameters and the whole body in parentheses.
Include guards (#ifndef/#define/#endif) or #pragma once stop a header being included twice. #ifdef enables debug-only code.
Code (C17)
#ifndef UTILS_H
#define UTILS_H
#define PI 3.14159
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#ifdef DEBUG
#define LOG(msg) printf("[debug] %s\n", msg)
#else
#define LOG(msg)
#endif
#endif
/* SQUARE(i++) still increments twice - prefer inline functions */Remember
- Parenthesise macro parameters.
- Macros have no type safety.
- Use include guards in every header.
Interview questions
Macro vs inline function?
Macros are text substitution without type checks and may evaluate args twice; inline functions are type-checked real functions the compiler may inline.
Output of #define SQ(x) x*x; SQ(2+3)?
2+3*2+3 = 11, not 25 — because the parameter wasn't parenthesised.
Lesson test
Take an 8-question test on “Preprocessor & Macros” — concepts, output prediction, bug spotting and interview questions.