條件編譯是 C 預處理器最強大的功能之一,實現**跨平台適配、調試開關、功能裁剪、版本管理**。本文系統講解三大核心指令(#ifdef, #ifndef, #if)、標準護衛宏模式、巢狀條件編譯、與 #define 配合的實戰技巧。
#ifdef IDENT / #ifndef IDENT
#ifdef DEBUG
printf("Debug mode\n");
#else
printf("Release mode\n");
#endif
#ifndef CONFIG_FEATURE_X
// 功能 X 未啟用,提供替代/報錯
#error "Feature X required!"
#endif
#ifdef:識別符**已定義**(無論值為何)編譯後續區塊。#ifndef:識別符**未定義**編譯後續區塊。#if EXPR:常量表達式判斷
#define VERSION 2
#if VERSION == 1
void legacy_api() { ... }
#elif VERSION == 2
void new_api() { ... }
#else
#error "Unsupported version"
#endif
EXPR 必須為**整型常量表達式**(可含 defined(ID) 運算符)。#elif、#else、#endif 多路分支。
// myheader.h
#ifndef MYHEADER_H_ // 慣例:大寫檔名 + _H_
#define MYHEADER_H_
// 介面聲明...
void foo(int);
#endif // MYHEADER_H_
#pragma once(非標準但廣泛支援),更簡潔。
// log.h
#ifdef DEBUG
#define LOG(fmt, ...) printf("[DEBUG][%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#else
#define LOG(fmt, ...) ((void)0) // 編譯期完全消除
#endif
// types.h
#if defined(__LP64__) || defined(_WIN64)
typedef long intptr_t;
typedef unsigned long uintptr_t;
#else
typedef int intptr_t;
typedef unsigned int uintptr_t;
#endif
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
#define HAS_CONSTEXPR 1
#else
#define HAS_CONSTEXPR 0
#endif
#if 0
// 大段舊代碼/實驗代碼,保留但不編譯
void old_algorithm() { ... }
#endif
defined() 運算符
#if defined(OS_LINUX) && defined(ARCH_X86_64)
// Linux x86_64 專用代碼
#elif defined(OS_WINDOWS) && defined(ARCH_ARM64)
// Windows ARM64 專用代碼
#else
#error "Unsupported OS/Arch combination"
#endif
defined(ID) 返回 1/0,可用於 #if 複雜邏輯組合。| 錯誤 | 後果 | 正確做法 |
|---|---|---|
#ifdef MACRO == 1 | 語法錯誤 | #if MACRO == 1 或 #if defined(MACRO) && MACRO == 1 |
宏定義在 #ifdef 之後 | 判斷失效 | 宏定義必須在條件編譯指令**之前**(或透過編譯器 -D 傳入) |
| 頭檔護衛巨集名衝突 | 誤屏蔽合法頭檔 | 使用專案前綴:MYPROJ_MYHEADER_H_ |
| 條件編譯區塊未閉合 | 編譯錯誤/後續代碼誤納入 | 每個 #if 必配 #endif,IDE 高亮輔助檢查 |
條件編譯是 C 語言**靈活性、可移植性、可配置性**的基石。掌握 #ifdef/#ifndef/#if 三板斧、護衛宏慣例、defined() 邏輯組合、調試/平台/版本開關模式,能讓你的代碼庫優雅支援多平台、多版本、多構建配置,且零運行時開銷。