預處理器(CPP)是編譯前獨立階段,進行純文本替換。掌握其指令、宏定義技巧與預定義宏,能極大提升代碼可移植性、可配置性與調試效率。
| 指令 | 功能 | 示例 |
|---|---|---|
#define | 定義宏(對象/函數式) | #define PI 3.14159 |
#include | 包含文件 | #include <stdio.h> |
#undef | 取消宏定義 | #undef PI |
#ifdef | 若宏已定義則編譯 | #ifdef DEBUG |
#ifndef | 若宏未定義則編譯 | #ifndef HEADER_H |
#if / #elif / #else / #endif | 條件編譯 | #if VERSION > 2 |
#error | 輸出錯誤並停止編譯 | #error "Unsupported platform" |
#pragma | 編譯器特定指令 | #pragma pack(1) |
#line | 修改行號/文件名 | #line 100 "gen.c" |
| 宏 | 含義 | 示例值 |
|---|---|---|
__DATE__ | 編譯日期 | "Jan 15 2025" |
__TIME__ | 編譯時間 | "14:30:00" |
__FILE__ | 當前文件名 | "main.c" |
__LINE__ | 當前行號 | 42 |
__STDC__ | ANSI C 合規標識 | 1 |
__STDC_VERSION__ | C 標準版本 | 199901L (C99) |
__STDC_HOSTED__ | 宿主/自由實現 | 1/0 |
**調試神技**:printf("DEBUG: %s:%d\n", __FILE__, __LINE__); 瞬間定位日誌來源。
\:宏定義跨行
#define MULTI_LINE \
do { \
foo(); \
bar(); \
} while(0)
#:將參數轉為字符串字面量
#define STR(x) #x
STR(hello) → "hello"
##:合併兩個標記
#define CONCAT(a, b) a##b
CONCAT(var, 1) → var1
defined():條件編譯中判斷宏是否定義
#if defined(DEBUG) && defined(LINUX)
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define SAFE_FREE(p) do { free(p); (p) = NULL; } while(0)
關鍵規範:
( **無空格**;do { ... } while(0) 包裹,保證分號語法正確;MAX(i++, j) 導致 i 自增兩次。__VA_ARGS__)#define LOG(fmt, ...) printf("[%s:%d] " fmt "\n", __FILE__, __LINE__, __VA_ARGS__)
LOG("value = %d", x);
##)#define DECL(n) int var##n;
DECL(1) DECL(2) → int var1; int var2;
#ifndef MY_HEADER_H
#define MY_HEADER_H
// ...
#endif
預處理器雖是「文本替換」,但善用條件編譯、字符串化、標記粘連與預定義宏,能實現**跨平台適配、編譯期計算、自動化日誌、代碼生成**等高級能力。切記:宏無類型、無作用域、無副作用保護,**能用 const/inline/constexpr 替代時優先替代**。