條件編譯四大支柱
| 指令 | 用途 | 典型場景 |
#ifdef / #ifndef | 檢查巨集是否定義 | 頭檔防重複包含、平台差異編譯 |
#if / #elif / #else / #endif | 常數表達式條件判斷 | 版本裁剪、功能開關、除錯模式 |
#undef | 取消巨集定義 | 重新定義、避免衝突、安全防禦 |
#error / #warning | 編譯期報錯/警告 | 強制配置檢查、不支援平台攔截 |
#undef:安全重新定義
#define MAX_SIZE 100
// ... 某處可能已定義 MAX_SIZE
#undef MAX_SIZE // 先取消,無論是否存在皆合法
#define MAX_SIZE 200 // 安全重新定義
#ifdef / #ifndef:頭檔防護標準模式
// 標準防護模式
#ifndef MY_HEADER_H
#define MY_HEADER_H
// 介面宣告...
#endif // MY_HEADER_H
// 替代寫法 (GCC/Clang/MSVC 支援)
#pragma once
#if / #elif / #else:多條件編譯控制
#if TARGET_OS_IPHONE
#import
#elif TARGET_OS_MAC
#import
#elif defined(_WIN32) || defined(_WIN64)
#include
#else
#error "Unsupported platform!"
#endif
// 數值比較
#if VERSION >= 2000
// 新版 API
#else
// 舊版相容
#endif
// 邏輯運算
#if defined(DEBUG) && !defined(NDEBUG)
#define LOG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define LOG(fmt, ...)
#endif
defined 運算子:靈活檢查定義狀態
// 等價於 #ifdef MACRO
#if defined(MACRO)
// 組合使用
#if defined(HAVE_SSL) && defined(HAVE_ZLIB)
// 同時擁有 SSL 與 ZLIB 支援
#endif
#error / #warning:編譯期斷言
#if !defined(CONFIG_H)
#error "config.h must be included first!"
#endif
#if __STDC_VERSION__ < 199901L
#warning "C99 features used, compiler may not fully support"
#endif
進階實戰技巧
1. 除錯/發布模式切換
#ifdef DEBUG
#define DBG_PRINT(fmt, ...) fprintf(stderr, "[DBG] %s:%d " fmt, __FILE__, __LINE__, ##__VA_ARGS__)
#define ASSERT(cond) if(!(cond)) { fprintf(stderr,"Assert failed: %s\n",#cond); abort(); }
#else
#define DBG_PRINT(fmt, ...)
#define ASSERT(cond)
#endif
2. 庫版本相容性
#if LIB_VERSION >= 0x020000 // 2.0.0
#define LIB_HAS_NEW_API 1
#define lib_new_func(...) lib_v2_func(__VA_ARGS__)
#else
#define LIB_HAS_NEW_API 0
#define lib_new_func(...) lib_v1_func(__VA_ARGS__)
#endif
3. 跨編譯器屬性支援
#if defined(__GNUC__) || defined(__clang__)
#define UNUSED __attribute__((unused))
#define NORETURN __attribute__((noreturn))
#elif defined(_MSC_VER)
#define UNUSED
#define NORETURN __declspec(noreturn)
#else
#define UNUSED
#define NORETURN
#endif
4. 靜態斷言 (C11 _Static_assert 替代)
#define STATIC_ASSERT(cond, msg) \
typedef char static_assert_failed_##msg[(cond) ? 1 : -1]
STATIC_ASSERT(sizeof(int) == 4, int_must_be_32bit);
STATIC_ASSERT(CHAR_BIT == 8, char_must_be_8bit);
常見陷阱與最佳實踐
| 陷阱 | 正確做法 |
| 在 #if 中使用未定義巨集直接比較 | 用 #if defined(MACRO) && MACRO > 0 或 #if MACRO (未定義視為 0) |
| #ifdef 檢查巨集值而非存在性 | #ifdef 只檢查是否定義,不檢查值。檢查值用 #if MACRO == 1 |
| 巨集定義在 #if 區塊內 | 巨集定義不受 #if 控制,建議集中在配置檔 |
| 巢狀 #if 混亂 | 保持淺層巢狀,用 #elif 扁平化 |
| 字串字面值在 #if 中比較 | 不可行,預處理器不識別字串,改用數值巨集 |
標準預定義巨集參考
__FILE__ // 當前檔案名
__LINE__ // 當前行號
__DATE__ // 編譯日期 "Mmm dd yyyy"
__TIME__ // 編譯時間 "hh:mm:ss"
__STDC__ // 標準 C 編譯器 (值 1)
__STDC_VERSION__ // C 版本: 199409L(C90), 199901L(C99), 201112L(C11)
__cplusplus // C++ 編譯器 (值如 201703L)
__GNUC__ // GCC 版本主號
_MSC_VER // MSVC 版本 (如 1920 = VS2019)
WIN32 / _WIN64 // Windows 平台
__APPLE__ // Apple 平台
__linux__ // Linux 平台
結語
條件編譯是 C/C++跨平台、多版本、可配置建構的基石。精通 #ifdef 防護、#if 邏輯裁剪、#undef 安全重定義、#error 編譯期斷言四大核心技法,配合 defined() 運算子靈活組合、標準預定義巨集識別環境、靜態斷言驗證假設,即能構建出在嵌入式裝置、桌面應用、伺服器叢集、行動裝置等多樣環境中穩健編譯、精準裁剪的專業級程式碼基礎設施。
- 上一篇文章: C語言演算法:蛇形填數矩陣生成
- 下一篇文章: C 語言宏定義深度解析:從符號常量到類函數宏與預處理運算符
Copyright ©
程式碼之家 All Rights Reserved