Preprocessor Directives
# CHAPTER 20
Preprocessor Directives
1. Introduction
Before the C Compiler translates your code into machine code, a program called the Preprocessor scans your file. It looks for lines starting with a hash symbol (#) and performs text substitutions or file inclusions. Understanding the preprocessor allows you to write cleaner, more configurable code.
2. Learning Objectives
By the end of this chapter, you will be able to:- Explain what the C Preprocessor does.
-
Use
#includefor system and user headers.
-
Create constants and Macros using
#define.
-
Use Conditional Compilation (
#ifdef,#ifndef).
3. The #include Directive
This directive tells the preprocessor to take the contents of another file and paste it exactly where the #include statement is.
-
Angle Brackets
< >: Used for standard system libraries. The compiler searches the default system directories.
#include <stdio.h>
-
Double Quotes
" ": Used for your own custom files. The compiler searches the current directory first.
#include "my_math.h"
4. The #define Directive (Constants)
Used to create symbolic constants. The preprocessor does a blind find-and-replace before compilation.
*Note: #define statements do not end with a semicolon!*
5. Macros with Arguments
You can use#define to create inline functions called Macros. Because they are handled by text substitution, they are faster than actual functions (no call stack overhead).
Why the extra parentheses? If you write #define SQUARE(x) x * x, and call SQUARE(3 + 2), it expands to 3 + 2 * 3 + 2 which equals 11, not 25! Extra parentheses ((3+2) * (3+2)) fix this.
6. Conditional Compilation
You can tell the preprocessor to include or exclude blocks of code based on certain conditions. This is heavily used for cross-platform development (e.g., compiling different code for Windows vs. Linux).If #define DEBUG exists, the debug printf is included in the final code. If it's removed, the preprocessor deletes the printf before the compiler even sees it!
7. Header Guards (#ifndef)
When working with multiple files, you might accidentally #include the same header file twice, causing "redefinition" errors. Header guards prevent this.
Inside my_math.h:
8. Memory-Level Explanation
Preprocessor directives do NOT use memory during runtime. They don't exist on the Stack or the Heap. They are purely text-replacement operations that happen during the initial stage of compilation. Therefore,#define MAX 100 doesn't take up any RAM like const int MAX = 100; would.
9. Common Mistakes
-
Adding a semicolon:
#define PI 3.14;->float x = PI * 2;expands tofloat x = 3.14; * 2;which is a syntax error.
-
Macro side effects:
SQUARE(i++)expands to((i++) * (i++)), incrementingitwice! Use macros carefully.
10. Exercises
-
1.
Create a macro
CUBE(x)and test it.
- 2. Write a program that uses conditional compilation to print "Windows" or "Linux" depending on which OS macro is defined at the top.
11. MCQ Quiz with Answers
When are preprocessor directives executed?
What is the difference between <stdio.h> and "stdio.h"?
Does #define MAX 100; have a syntax error in the directive itself?
Macros are evaluated by:
What does #ifdef mean?
Header guards (#ifndef) are used to prevent:
Why use macros with arguments instead of functions?
If #define MULT(a, b) a * b, what is MULT(2+3, 4)?
Do preprocessor macros exist in memory during runtime?
12. Interview Questions
- Q: What is the difference between a Macro and a Function? When would you use which?
-
Q: How do header guards (
#ifndef,#define,#endif) work?
-
Q: Explain why
#define SQUARE(x) x*xis dangerous.
13. Summary
The C Preprocessor modifies source code before the compiler translates it.#include pastes files, #define creates constants and fast macro functions, and #ifdef conditionally includes code blocks. Mastering these directives is key to writing professional, multi-file C applications.
14. Next Chapter Recommendation
In Chapter 21: Command Line Arguments, we will learn how to pass data directly into ourmain() function when we run our program from the terminal.