條件編譯是跨平台、多配置、調試發布切換的核心手段。本文系統整理 #ifdef/#ifndef/#if 三大模式、嵌套技巧、實戰代碼片段與最佳實踐。
#ifdef DEBUG
printf("Debug: x=%d\n", x);
#else
// 發布版無輸出
#endif
用途:調試代碼、功能開關、平台特定代碼
#ifndef CONFIG_H
#define CONFIG_H
// 頭文件內容
#endif
用途:頭文件防重複包含(標準守衛模式)
#if VERSION >= 2
new_feature();
#elif VERSION == 1
legacy_feature();
#else
#error "Unsupported version"
#endif
用途:版本號判斷、數值比較、複雜邏輯組合
#if((LCD_Type == LCDW35) || (LCD_Type == LCDS35))
// 3.5寸寬屏
extern unsigned char TQ_LOGO_320240[];
#elif(LCD_Type == LCDT35)
// 3.5寸另一型號
extern unsigned char TQ_LOGO_240320[];
#elif(LCD_Type == LCDW43)
// 4.3寸
extern unsigned char TQ_LOGO_480272[];
#elif(LCD_Type == VGA)
// VGA
extern unsigned char TQ_LOGO_640480[];
#elif(LCD_Type == LCDA70)
// 7寸
extern unsigned char TQ_LOGO_800480[];
#endif
✅ 編譯期根據 LCD_Type 宏選擇唯一一組圖片符號,無運行時開銷。
#if defined(DEBUG) && defined(LINUX)
// 同時滿足
#endif
#if defined(FOO) || defined(BAR)
// 任一滿足
#endif
#ifdef PLATFORM_A
#ifdef FEATURE_X
// A+X
#else
// A+非X
#endif
#else
// 非A
#endif
#error "不支援的平台"
#warning "此功能即將棄用"
| 原則 | 說明 |
|---|---|
| 宏名全大寫 + 前綴 | MYAPP_DEBUG 避免衝突 |
| 優先用 #if 而非 #ifdef | 表達式更清晰,支援數值比較 |
| 頭文件必須用 #ifndef 守衛 | 防止重複包含導致重定義錯誤 |
| 避免深層嵌套 | 超過 3 層考慮重構或拆分文件 |
| 配置集中管理 | 建立 config.h 統一定義 |
| 編譯器命令行定義 | -DDEBUG=1 替代源碼修改 |
// ❌ 錯誤:#ifdef 不能直接判斷數值
#ifdef VERSION > 1 // 只檢查 VERSION 是否定義,忽略 > 1
// ✅ 正確:
#if VERSION > 1
// ❌ 錯誤:宏未定義時值為 0,但 #ifdef 行為不同
#define VAL 0
#ifdef VAL // 真(已定義)
#if VAL // 假(值為0)
#endif
gcc -E source.c -o source.i // 展開所有宏、條件編譯
cl /E source.c // MSVC
檢查 .i 文件確認條件編譯是否按預期生效。