← C EnglishChapter 11 of 13

Preprocessor Directives

## Learning Objectives - Understand the C preprocessor - Master include directives - Work with macros - Use conditional compilation ## Preprocessor Overview The preprocessor runs before compilation, transforming source code. ```c #define PI 3.14159 ``` Becomes: ```c 3.14159 ``` ## Include Directives ### #include ```c #include // System header #include "myheader.h" // User header ``` ### Include Guards ```c // myheader.h #ifndef MYHEADER_H #define MYHEADER_H // Header contents #endif ``` ### #pragma once (Modern) ```c // myheader.h #pragma once // Header contents ``` ## Macro Definition ### Object-like Macros ```c #define PI 3.14159 #define MAX_SIZE 100 #define TRUE 1 #define FALSE 0 ``` ### Function-like Macros ```c #define SQUARE(x) ((x) * (x)) int result = SQUARE(5); // 25 ``` ### Multiple Arguments ```c #define MAX(a, b) ((a) > (b) ? (a) : (b)) int m = MAX(10, 20); // 20 ``` ### Why Use Parentheses? ```c // Without parentheses #define SQUARE(x) x * x int result = SQUARE(5); // 25 (correct) int result = SQUARE(2 + 3); // 2 + 3 * 2 + 3 = 11 (WRONG!) // With parentheses #define SQUARE(x) ((x) * (x)) int result = SQUARE(2 + 3); // ((2 + 3) * (2 + 3)) = 25 (correct) ``` ## Token Concatenation ### Token Concatenation Operator ```c #define CONCAT(a, b) a ## b int xy = 10; CONCAT(x, y); // Expands to xy ``` ## Stringification ### Stringification Operator ```c #define PRINT_INT(x) printf(#x " = %d\n", x) int value = 42; PRINT_INT(value); // Expands to: // printf("value" " = %d\n", value); ``` ## Conditional Compilation ### #ifdef / #ifndef ```c #define DEBUG 1 #ifdef DEBUG printf("Debug mode\n"); #endif #ifndef PI #define PI 3.14159 #endif ``` ### #if / #else / #elif ```c #if __STDC_VERSION__ >= 201112L // C11 or later printf("C11 or later\n"); #elif __STDC_VERSION__ >= 199901L // C99 printf("C99\n"); #else // C89/C90 printf("C89/C90\n"); #endif ``` ### Defined Operator ```c #if defined(DEBUG) && DEBUG > 0 printf("Debug level: %d\n", DEBUG); #endif // Short form: #if defined(DEBUG) // ... #endif // Even shorter: #ifdef DEBUG // ... #endif ``` ## Predefined Macros | Macro | Description | |-------|-------------| | `__FILE__` | Current file name | | `__LINE__` | Current line number | | `__DATE__` | Compilation date | | `__TIME__` | Compilation time | | `__STDC__` | Conforms to ISO C | | `__STDC_VERSION__` | C standard version | | `__func__` | Current function name | ```c #include int main(void) { printf("File: %s\n", __FILE__); printf("Line: %d\n", __LINE__); printf("Date: %s\n", __DATE__); printf("Time: %s\n", __TIME__); printf("Function: %s\n", __func__); return 0; } ``` ## Assert Macro ```c #include int divide(int a, int b) { assert(b != 0); // Fails if b is 0 return a / b; } ``` ### Disable Assertions ```c #define NDEBUG // Disable assertions #include ``` ## Variadic Macros ```c #define DEBUG(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) DEBUG("Error %d: %s\n", errno, strerror(errno)); ``` ### Empty Variadic Argument ```c #define LOG(fmt, ...) printf(fmt, ##__VA_ARGS__) LOG("Hello\n"); // Works LOG("Value: %d\n", 42); // Works ``` ## Undefining Macros ```c #define PI 3.14159 printf("%f\n", PI); #undef PI #define PI 3.14 // Redefine is now allowed ``` ## Preprocessor Operators ### #pragma ```c #pragma pack(push, 1) struct Packed { char c; int x; }; #pragma pack(pop) ``` ### _Pragma ```c _Pragma("pack(push, 1)") struct Packed { char c; int x; }; _Pragma("pack(pop)") ``` ## Common Patterns ### Header Guards ```c // math_utils.h #ifndef MATH_UTILS_H #define MATH_UTILS_H int add(int a, int b); int subtract(int a, int b); #endif ``` ### Platform Detection ```c #ifdef _WIN32 // Windows #include #elif __linux__ // Linux #include #elif __APPLE__ // macOS #include #endif ``` ### Feature Testing ```c #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200809L // Use POSIX functions #endif ``` ### Debug Logging ```c #define DEBUG #ifdef DEBUG #define LOG(fmt, ...) fprintf(stderr, "[%s:%d] " fmt "\n", \ __FILE__, __LINE__, ##__VA_ARGS__) #else #define LOG(fmt, ...) // Empty in release #endif ``` ### Deprecation ```c #define DEPRECATED __attribute__((deprecated)) DEPRECATED void oldFunction(void) { // ... } ``` ## Macro vs Function | Aspect | Macro | Function | |--------|-------|----------| | Speed | Faster (no call overhead) | Slower | | Type | Generic (text substitution) | Type-safe | | Debug | Harder | Easier | | Arguments | Evaluated each use | Evaluated once | ## Summary - Preprocessor runs before compilation - `#include` brings in header files - Use include guards or `#pragma once` - `#define` creates macros - Function macros should use parentheses - `#ifdef`/`#if` for conditional compilation - Predefined macros: `__FILE__`, `__LINE__`, `__DATE__` - `NDEBUG` disables assertions - Variadic macros: `__VA_ARGS__`

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →