0.2: The C Preprocessor

Theory Unit 0: C Prerequisites · ~20 min

The first program to run before your code is the preprocessor. It happens before compilation.

Every line that starts with # is a preprocessor directive,an instruction to the preprocessor, not to the compiler. It's good knowledge to know how these work.

What does the preprocessor do?

Three things:

  1. File inclusion: #include copy and pastes entire files into your code
  2. Macro expansion: #define does text replacement before compilation
  3. Conditional compilation: #ifdef/#ifndef lets you include or exclude code at compile time

1. #include

When you write #include <stdio.h>, the preprocessor finds the file stdio.h on your system and pastes its entire contents into your file at that exact spot.

That's why it's called a header file, hence the .h extension. It goes at the head (top) of your code.

  • #include <file.h>: searches system directories (standard library headers)
  • #include "file.h": searches your project directory first, then system directories

Quick reference

Angle brackets = System include
Quotations = Project Directory

2. #define: Text replacement

The #define directive tells the preprocessor to replace every occurrence of a name with something else. Kind of like find and replace. It's purely textual.

Constant examples

#define MAX_HEALTH 100 replaces every MAX_HEALTH in your code with 100. No variable is created. It's as if you typed 100 everywhere yourself.

Function-like macros

#define SQUARE(x) ((x) * (x)) looks like a function, but it's not. It's again just text substitution. The parentheses around (x) are extremely important to avoid bugss.

⚠️ Warning:

Macros don't check types and can cause bugs. That's why modern C prefers const variables and inline functions. Still, macros are still everywhere in real C code. It's important that you get a baseline understanding of it now.

3. Conditional compilation

The preprocessor can include or exclude entire blocks of code based on whether a macro is defined:

  • #ifdef NAME —> reads like: "if NAME is defined"
  • #ifndef NAME —> reads like: "if NAME is NOT defined" (very common in header guards)
  • #if, #elif, #else, #endif —> full conditional logic, similar to the if keyword you learned in 0.1.

This is how C code gets compiled differently on different operating systems, or how debug logging gets stripped from release builds.

Again, we'll go over conditionals in more depth in later units. Just know that you can do this.

Your task

The code on the right demonstrates all three preprocessor features.
1. Run the code and check the output
2. Try changing SQUARE(2+1) —> do you get the result you expect?
3. Change DEBUG to see how conditional compilation works
4. Check the Assembly tab —> notice how the preprocessor constants become literal numbers in the compiled output

Output
Press Run to execute your code.