C Preprocessor Directives
Code that runs before compilation! Learn #include, #define macros, and conditional compilation with #ifdef.
What You Will Learn
- ✓Include header files correctly
- ✓Create macros with #define
- ✓Use conditional compilation
- ✓Understand header guards
01What is the Preprocessor?
📝 Definition
The C Preprocessor is a tool that processes your code before compilation. It handles directives that start with # - like including files, defining constants, and conditional compilation.
🔄 Compilation Process
Source Code
.c file
Preprocessor
#include, #define
Compiler
Translation
Executable
.exe / a.out
💡 Key Preprocessor Directives
- •
#include- Include header files - •
#define- Define macros and constants - •
#ifdef / #ifndef / #endif- Conditional compilation - •
#pragma- Compiler-specific instructions
02#include Directive
The #include directive tells the preprocessor to copy the contents of another file into your code. There are two forms:
<angle brackets>
#include <stdio.h>#include <stdlib.h>#include <string.h>Used for standard library headers. Searches system include directories.
"double quotes"
#include "myheader.h"#include "utils/helper.h"#include "../config.h"Used for your own headers. Searches current directory first.
Creating Your Own Header File
1// mymath.h - Header file (declarations)2#ifndef MYMATH_H // Header guard - prevents double inclusion3#define MYMATH_H45// Function declarations (prototypes)6int add(int a, int b);7int subtract(int a, int b);8int multiply(int a, int b);910#endif1// mymath.c - Implementation file (definitions)2#include "mymath.h"34int add(int a, int b) {5 return a + b;6}78int subtract(int a, int b) {9 return a - b;10}1112int multiply(int a, int b) {13 return a * b;14}1// main.c - Using the header2#include <stdio.h>3#include "mymath.h"45int main() {6 printf("5 + 3 = %d\n", add(5, 3));7 printf("5 - 3 = %d\n", subtract(5, 3));8 printf("5 * 3 = %d\n", multiply(5, 3));9 return 0;10}03#define Macros
The #define directive creates macros - text replacements done by the preprocessor before compilation.
Simple Constants
1#include <stdio.h>23// Define constants4#define PI 3.141595#define MAX_SIZE 1006#define GREETING "Hello, World!"78int main() {9 double area = PI * 5 * 5; // PI replaced with 3.1415910 int arr[MAX_SIZE]; // MAX_SIZE replaced with 10011 printf("%s\n", GREETING); // GREETING replaced with string12 return 0;13}Macros with Parameters
1#include <stdio.h>23// Macro functions (no function call overhead)4#define SQUARE(x) ((x) * (x))5#define MAX(a, b) ((a) > (b) ? (a) : (b))6#define MIN(a, b) ((a) < (b) ? (a) : (b))7#define ABS(x) ((x) < 0 ? -(x) : (x))89int main() {10 int n = 5;11 printf("Square of %d: %d\n", n, SQUARE(n)); // Output: 2512 printf("Max(3, 7): %d\n", MAX(3, 7)); // Output: 713 printf("Min(3, 7): %d\n", MIN(3, 7)); // Output: 314 printf("Abs(-10): %d\n", ABS(-10)); // Output: 1015 return 0;16}⚠️ Macro Pitfall: Always Use Parentheses!
// BAD - No parentheses#define SQUARE_BAD(x) x * x// Problem: SQUARE_BAD(3+2) expands to 3+2 * 3+2 = 3+6+2 = 11 (WRONG!)// GOOD - With parentheses#define SQUARE_GOOD(x) ((x) * (x))// SQUARE_GOOD(3+2) expands to ((3+2) * (3+2)) = 5 * 5 = 25 (CORRECT!)#undef - Undefine a Macro
#define DEBUG 1// ... code that uses DEBUG ...#undef DEBUG // Now DEBUG is undefined// DEBUG no longer exists here04Conditional Compilation
Conditionally include or exclude code based on defined macros. Useful for debugging, platform-specific code, and feature flags.
#ifdef / #ifndef / #endif
1#include <stdio.h>23#define DEBUG // Comment this line to disable debug mode45int main() {6 int x = 10;7 8 #ifdef DEBUG9 printf("[DEBUG] x = %d\n", x); // Only compiled if DEBUG is defined10 #endif11 12 printf("Result: %d\n", x * 2);13 14 #ifndef RELEASE15 printf("[DEV] Development build\n"); // Only if RELEASE is NOT defined16 #endif17 18 return 0;19}#if / #elif / #else / #endif
1#include <stdio.h>23#define VERSION 245int main() {6 #if VERSION == 17 printf("Running Version 1\n");8 #elif VERSION == 29 printf("Running Version 2\n");10 #else11 printf("Unknown Version\n");12 #endif13 14 #if defined(DEBUG) && VERSION >= 215 printf("Debug mode for V2+\n");16 #endif17 18 return 0;19}Platform-Specific Code
1#include <stdio.h>23void clearScreen() {4 #ifdef _WIN325 system("cls"); // Windows6 #else7 system("clear"); // Linux/Mac8 #endif9}1011int main() {12 #if defined(_WIN32) || defined(_WIN64)13 printf("Running on Windows\n");14 #elif defined(__linux__)15 printf("Running on Linux\n");16 #elif defined(__APPLE__)17 printf("Running on macOS\n");18 #else19 printf("Unknown platform\n");20 #endif21 22 return 0;23}05Header Guards
Header guards prevent a header file from being included multiple times, which would cause "redefinition" errors.
❌ Without Header Guard
// myheader.hstruct Point { int x, y;};// If included twice:// ERROR: redefinition of 'struct Point'✅ With Header Guard
// myheader.h#ifndef MYHEADER_H#define MYHEADER_Hstruct Point { int x, y;};#endif // MYHEADER_H💡 Modern Alternative: #pragma once
// myheader.h#pragma once // Non-standard but widely supportedstruct Point { int x, y;};#pragma once is simpler but not part of the C standard. Traditional header guards are more portable.
06Common Mistakes
❌ Mistake 1: Semicolon after #define
// WRONG#define MAX 100; // Semicolon included in replacement!int arr[MAX]; // Becomes: int arr[100;]; - ERROR!// CORRECT#define MAX 100int arr[MAX]; // Becomes: int arr[100];❌ Mistake 2: Space in macro name
// WRONG#define MAX VALUE 100 // 'MAX' is defined as 'VALUE 100'// CORRECT#define MAX_VALUE 100❌ Mistake 3: Missing parentheses in macro
// WRONG#define DOUBLE(x) x + xint result = DOUBLE(5) * 2; // 5 + 5 * 2 = 5 + 10 = 15 (WRONG!)// CORRECT#define DOUBLE(x) ((x) + (x))int result = DOUBLE(5) * 2; // ((5) + (5)) * 2 = 10 * 2 = 20❌ Mistake 4: Side effects in macro arguments
#define SQUARE(x) ((x) * (x))int a = 5;int result = SQUARE(a++); // Expands to: ((a++) * (a++))// a is incremented TWICE! Result is undefined behavior.// Solution: Use inline functions for complex operations07Summary
What You Learned:
- ✓#include: Include header files (use <> for standard, "" for your own)
- ✓#define: Create constants and macro functions
- ✓Conditional: #ifdef, #ifndef, #if, #elif, #else, #endif
- ✓Header Guards: Prevent multiple inclusion with #ifndef/#define/#endif
- ✓Best Practices: Always use parentheses in macros, no semicolons in #define