The preprocessor handles directives beginning with # before compilation. It can define symbols, keep code conditionally, and include header contents. This is a textual preparation stage, so it does not understand variable types.
Macros
A macro replaces a name with text. Macros used as constants conventionally use uppercase names.
#include <iomanip>
#include <iostream>
#define PI 3.1415926
double circle_area(double radius) {
return PI * radius * radius;
}
int main() {
double radius = 3.0;
std::cout << std::fixed << std::setprecision(2);
std::cout << "area = " << circle_area(radius) << '\n';
return 0;
}Function-like macros
A function-like macro resembles a function call, but creates no stack frame and performs no type checking. Arguments may be full expressions, so parenthesize every parameter use and the complete result. Avoid side-effecting arguments such as i++ when a macro repeats its parameter.
#include <iostream>
#define SQUARE(x) ((x) * (x))
int main() {
int n = SQUARE(3 + 1);
std::cout << "n = " << n << '\n';
return 0;
}KNOWLEDGE QUIZ
Macro expansion conveyor
Replace both occurrences of the SQUARE parameter, then follow the parentheses during evaluation. The preprocessor replaces text; it does not calculate values.
SQUARE is the macro name. The entire text 3 + 1 is the argument; no arithmetic happens yet.
Conditional compilation
#if selects source code when its condition is true, #else provides the alternative, and #endif closes the conditional group. These directives run before compilation, unlike a runtime if/else.
This circle-area calculator has two build modes: a debug build shows the radius and calculation result, while a release build shows only the area the user needs. Change DEBUG and recompile to switch the output.
#include <iomanip>
#include <iostream>
#define PI 3.1415926
#define DEBUG 1
int main() {
double radius = 3.0;
double area = PI * radius * radius;
std::cout << std::fixed << std::setprecision(2);
#if DEBUG
std::cout << "[DEBUG] radius = " << radius << ", area = " << area << '\n';
#else
std::cout << "Area: " << area << '\n';
#endif
return 0;
}With DEBUG set to 1, the preprocessor keeps the #if branch and the output is [DEBUG] radius = 3.00, area = 28.27. Set it to 0 and recompile to keep only the #else branch, producing Area: 28.27. The unselected branch is not compiled.
#ifdef and #ifndef check whether a macro is defined; the next section uses #ifndef to protect a header.
KNOWLEDGE QUIZ
A circle calculator with switchable debugging
Build a circle calculator with switchable debug output.
- Define PI, SQUARE(x), and DEBUG.
- Read a radius and calculate the area and squared diameter.
- Print the original radius only when DEBUG is 1.
- Change DEBUG to 0 and confirm the debug line disappears.