The C Preprocessor & Macros
The C preprocessor runs before your code is compiled. It is a text-processing step that handles lines starting with # — pulling in header files, replacing macros, and conditionally including code. Understanding it explains what #include <stdio.h> at the top of every program actually does.
#include: pulling in headers
#include copies the contents of another file into your source before compilation. Angle brackets search the system directories; quotes search your project first:
#include <stdio.h> /* system header: standard input/output */
#include "myutils.h" /* your own header in the project */
This is why you can call printf — its declaration lives in stdio.h, and #include brings it in.
#define: constants and macros
#define creates a macro: the preprocessor finds the name and replaces it with the text you gave, everywhere it appears.
#include <stdio.h>
#define PI 3.14159 /* object-like macro: a named constant */
#define SQUARE(x) ((x) * (x)) /* function-like macro */
int main(void) {
double area = PI * SQUARE(2.0); /* becomes ((2.0)*(2.0)) */
printf("Area: %.2f\n", area); /* 12.57 */
return 0;
}
A macro is pure text substitution — there is no type checking and no function call. Those parentheses around x and the whole expression are essential (see the mistakes below).
Why so many parentheses?
Without them, substitution can break math. #define SQUARE(x) x * x turns SQUARE(2 + 3) into 2 + 3 * 2 + 3 = 11, not 25. Wrapping everything — ((x) * (x)) — gives ((2 + 3) * (2 + 3)) = 25. Always parenthesize macro parameters and the full body.
For typed constants, many programmers prefer const (a real variable the compiler checks) over #define for values, reserving macros for things const can't do.
Want to learn this properly?
Join the waitlist for C Programming — beginner-friendly, project-first classes in Jalgaon.
Explore C ProgrammingConditional compilation
#if, #ifdef, #ifndef, #else, #endif let you include or skip code at compile time — useful for debug builds or platform differences:
#define DEBUG 1
#if DEBUG
printf("Debug: value is %d\n", value); /* compiled only when DEBUG is 1 */
#endif
Include guards
If two files both #include "myutils.h", its contents could be pasted twice and cause errors. An include guard prevents that:
/* top of myutils.h */
#ifndef MYUTILS_H
#define MYUTILS_H
/* declarations go here -- included only once */
#endif /* MYUTILS_H */
The first time the file is included, MYUTILS_H isn't defined, so the body is processed and the macro gets defined. Any later include sees it's already defined and skips the body. Every header you write should have one.
Common mistakes
- Missing parentheses in macros, causing precedence bugs like the
SQUAREexample above. - Putting a semicolon after a macro definition:
#define MAX 100;pastes the;everywhere, breaking expressions. - Side effects in macro arguments:
SQUARE(i++)expands to((i++) * (i++)), incrementingitwice — undefined behaviour. Prefer a function when arguments have side effects. - No include guard in your headers, causing duplicate-definition errors.
- Treating macros like variables — they have no type and no scope rules; they're raw text.
FAQ
Macro or const? For simple typed constants, prefer const (type-safe, debuggable). Use macros for conditional compilation, include guards, and code generation.
Does the preprocessor understand C syntax? No — it only does text manipulation. The compiler sees the result afterwards.
Continue at the hub C Programming, then Functions in C and Variables & Data Types.
Want to learn this properly? Join the waitlist for our C Programming course — taught in Jalgaon.
Want to learn this properly?
Join the waitlist for C Programming — beginner-friendly, project-first classes in Jalgaon.
Explore C ProgrammingFounder, Infoplanet
Atul Kabra founded Infoplanet in 2001 and has spent over two decades teaching programming — C, C++, Java, databases and more — to students across Maharashtra.
Related guides
Arrays in C
A beginner guide to arrays in C — declaring, initializing and indexing them, looping over elements, multidimensional arrays, and avoiding out-of-bounds errors.
Common C Errors & How to Fix Them
A troubleshooting guide to the most common C errors beginners face — from = vs ==, format mismatches and missing semicolons to segmentation faults — and how to fix each.
Dynamic Memory Allocation in C
A beginner guide to dynamic memory allocation in C — malloc, calloc, realloc and free, allocating at runtime, and preventing memory leaks.
