The C Preprocessor
By Flavio
Tagged: C
Learn how the C preprocessor works, resolving #include directives, substituting #define constants, and handling conditionals like #if before compiling.
The preprocessor is a tool that helps us a lot when programming with C. It is part of the C Standard, just like the language, the compiler and the standard library.
It parses our program and makes sure that the compiler gets all the things it needs before going on with the process.
What does it do, in practice?
For example, it looks up all the header files you include with the #include directive.
It also looks at every constant you defined using #define and substitutes it with its actual value.
That’s just the start, and I mentioned those 2 operations because they are the most common ones. The preprocessor can do a lot more.
Did you notice #include and #define have a # at the beginning? That’s common to all the preprocessor directives. If a line starts with #, that’s taken care by the preprocessor.
Conditionals
One of the things we can do is to use conditionals to change how our program will be compiled, depending on the value of an expression.
For example we can check if the DEBUG constant is 0:
#include <stdio.h>
#define DEBUG 0
int main(void) {
#if DEBUG == 0
printf("I am NOT debugging\n");
#else
printf("I am debugging\n");
#endif
}
A const variable cannot drive #if. The preprocessor runs before compilation, so it does not see C variables. An unknown identifier inside #if is replaced with 0. That is why #define DEBUG 0 is the right tool here.
Symbolic constants
We can define a symbolic constant:
#define VALUE 1
#define PI 3.14
#define NAME "Flavio"
When we use NAME or PI or VALUE in our program, the preprocessor replaces its name with the value, before compiling the program.
Symbolic constants are very useful because we can give names to values without creating variables at compilation time.
Macros
With #define we can also define a macro. The difference between a macro and a symbolic constant is that a macro can accept an argument and typically contains code, while a symbolic constant is a value:
#define POWER(x) ((x) * (x))
Notice the parentheses around the arguments, a good practice to avoid issues when the macro is replaced in the precompilation process.
Then we can use it in our code like this:
printf("%u\n", POWER(4)); //16
The big difference with functions is that macros do not specify the type of their arguments or return values, which might be handy in some cases.
If defined
We can check if a symbolic constant or a macro is defined using #ifdef:
#include <stdio.h>
#define VALUE 1
int main(void) {
#ifdef VALUE
printf("Value is defined\n");
#else
printf("Value is not defined\n");
#endif
}
We also have #ifndef to check for the opposite (macro not defined).
We can also use #if defined and #if !defined to do the same task.
It’s common to wrap some block of code into a block like this:
#if 0
#endif
to temporarily prevent it to run, or to use a DEBUG symbolic constant:
#define DEBUG 0
#if DEBUG
//code only sent to the compiler
//if DEBUG is not 0
#endif
Predefined symbolic constants you can use
The preprocessor also defines a number of symbolic constants you can use, identified by the 2 underscores before and after the name, including:
__LINE__translates to the current line in the source code file__FILE__translates to the name of the file__DATE__translates to the compilation date, in theMmm dd yyyyformat (e.g.Oct 28 2026)__TIME__translates to the compilation time, in thehh:mm:ssformat__STDC_VERSION__is the language version the compiler is using. In C23 mode it is202311L
What C23 added
C23 (ISO/IEC 9899:2024) added a few preprocessor features.
#elifdef and #elifndef sit next to #elif when you want to test if a name is defined. #warning is now a standard directive, not a compiler extension. #embed pulls a binary file’s bytes into an initializer list. __has_include and __has_c_attribute let you test for a header or an attribute before you use it.
GCC 15 supports #embed and defaults to C23 (-std=gnu23).
Want me to talk about your product? You can sponsor this site.