在調試、跨平台移植、版本裁剪等場景下,我們希望通過修改幾個宏開關,就能生成不同功能的二進制,而不必維護多份代碼副本。條件編譯在預處理階段選擇代碼片段,未被選中的代碼完全不參與編譯,節省空間、避免衝突。
#if / #elif / #else / #endif 表達式條件
#if CONDITION_1
// 代碼段 1
#elif CONDITION_2
// 代碼段 2
...
#else
// 默認代碼段
#endif
#else 分支#ifdef / #ifndef 宏定義檢查
// 如果定義了 MACRO
#ifdef MACRO
// 代碼段 1
#else
// 代碼段 2
#endif
// 如果未定義 MACRO(效果等價)
#ifndef MACRO
// 代碼段 2
#else
// 代碼段 1
#endif
-Ddefined() 運算符:構建複雜邏輯
#if defined(MACRO1) || (!defined(MACRO2) && defined(MACRO3))
// 複雜組合條件
#else
// 其他情況
#endif
#if 中任意組合邏輯運算#if 實現多版本一鍵切換
#define MY_PRINTF_VERSION 2
#if MY_PRINTF_VERSION == 1
void printf_simple(char *str) { ... }
#elif MY_PRINTF_VERSION == 2
int printf_full(char *fmt, ...) { ... }
#elif MY_PRINTF_VERSION == 3
int printf_com(unsigned char port, char *str) { ... }
#else
// 默認版本
#endif
只需改一個數字即可切換版本,避免手動註釋/取消註釋代碼塊帶來的錯誤風險。
config.h + 默認值保護
// config.h
#define MY_PRINTF_VERSION 1
// 源文件
#include "config.h"
#if !defined(MY_PRINTF_VERSION)
#define MY_PRINTF_VERSION 1 // 提供默認值
#endif
#if MY_PRINTF_VERSION == 1
...
#elif MY_PRINTF_VERSION == 2
...
#endif
config.h,核心代碼無需變動!defined() 防止遺漏定義導致誤觸發默認分支假設舊版本有 v1、v2、v3,新版只保留 v2、v3,但舊配置可能仍設為 v1:
// 方法 A:條件合併
#if MY_PRINTF_VERSION == 2 || MY_PRINTF_VERSION == 1
// v2 實現兼容 v1
#elif MY_PRINTF_VERSION == 3
...
#endif
// 方法 B:用 #undef 重定向(更乾淨)
#if MY_PRINTF_VERSION == 1
#undef MY_PRINTF_VERSION
#define MY_PRINTF_VERSION 2
#endif
#if MY_PRINTF_VERSION == 2
...
#elif MY_PRINTF_VERSION == 3
...
#endif
#if 能捕獲宏名拼寫錯誤若誤寫 #define MY_PRINT_EN 為 MY_PRINTF_EN:
#ifdef MY_PRINTF_EN 或 #if defined(MY_PRINTF_EN) → 靜默失效,難排查#if MY_PRINTF_EN == 1 → 編譯器報警「MY_PRINTF_EN 未定義」,立即定位錯誤| 場景 | 推薦方案 |
|---|---|
| 簡單開關、單一宏 | #ifdef / #ifndef |
| 多宏組合邏輯、需可維護性 | #if defined() 組合 |
| 數值比較、版本號、範圍判斷 | #if 表達式 |
| 需捕獲拼寫錯誤、嚴格類型檢查 | #if MACRO == VALUE |
條件編譯是 C 語言實現代碼複用、多平台適配、版本管理的利器。掌握 #if、#ifdef、defined() 三種形式的優缺點,結合配置文件與默認值策略,能構建清晰、可維護、抗錯誤的編譯配置體系。