首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言條件編譯完全指南:#ifdef、#ifndef、#if、#elif、#else、#endif 實戰模式

     編輯:關於C語言

條件編譯三大核心指令

指令用途典型場景
`#ifdef` / `#ifndef`檢查宏**是否定義**防重複包含、平台專用代碼、功能開關
`#if` / `#elif` / `#else`檢查**常數表達式真假**版本比較、數值範圍、複雜邏輯組合
`#endif`結束條件區塊配對使用,不可省略

模式一:防重複包含衛兵 (Header Guard)


/* mylib.h */
#ifndef MYLIB_H
#define MYLIB_H

/* 介面宣告 */
void mylib_init(void);

#endif /* MYLIB_H */

現代替代:`#pragma once` (GCC/Clang/MSVC 全支援),更簡潔無命名衝突風險。

模式二:平台抽象層


/* platform.h */
#if defined(_WIN32) || defined(_WIN64)
    #define PLATFORM_WINDOWS 1
    #define DLLEXPORT __declspec(dllexport)
    #include 
#elif defined(__linux__)
    #define PLATFORM_LINUX 1
    #define DLLEXPORT __attribute__((visibility("default")))
    #include 
#elif defined(__APPLE__)
    #define PLATFORM_MACOS 1
    #define DLLEXPORT __attribute__((visibility("default")))
#else
    #error "Unsupported platform"
#endif

模式三:編譯期配置開關


/* config.h - 專案統一配置 */
#define ENABLE_LOGGING 1
#define ENABLE_STATS   0
#define MAX_CONNECTIONS 1024
#define PROTOCOL_VERSION 2

/* 業務代碼 */
#if ENABLE_LOGGING
    #define LOG(fmt, ...) fprintf(stderr, "[LOG] " fmt "\n", ##__VA_ARGS__)
#else
    #define LOG(fmt, ...) ((void)0)
#endif

#if PROTOCOL_VERSION >= 2
    #define HEADER_SIZE 16
#else
    #define HEADER_SIZE 8
#endif

編譯時可覆蓋:`gcc -DENABLE_STATS=1 -DPROTOCOL_VERSION=3 ...`

模式四:版本區間與功能矩陣


#if VERSION_MAJOR > 2 || (VERSION_MAJOR == 2 && VERSION_MINOR >= 5)
    #define FEATURE_NEW_API 1
#else
    #define FEATURE_NEW_API 0
#endif

#if defined(FEATURE_A) && defined(FEATURE_B) && !defined(FEATURE_C)
    #define COMBO_AB_ONLY 1
#endif

模式五:編譯期斷言與錯誤攔截


/* C11 標準靜態斷言 */
_Static_assert(sizeof(int) == 4, "int_must_be_32bit");
_Static_assert(MAX_CONNECTIONS > 0, "max_conn_positive");

/* 舊標準相容技巧 */
#define COMPILE_TIME_ASSERT(cond, msg) \
    typedef char assert_##msg[(cond) ? 1 : -1]

COMPILE_TIME_ASSERT(CHAR_BIT == 8, char_is_8bit);

模式六:除錯/發布模式切換


#ifdef NDEBUG
    #define ASSERT(cond) ((void)0)
    #define TRACE(fmt, ...) ((void)0)
#else
    #define ASSERT(cond) \
        do { if (!(cond)) { fprintf(stderr, "ASSERT: %s:%d: %s\n", __FILE__, __LINE__, #cond); abort(); } } while(0)
    #define TRACE(fmt, ...) fprintf(stderr, "[TRACE] " fmt "\n", ##__VA_ARGS__)
#endif

發布編譯:`gcc -DNDEBUG -O2 ...` 自動移除斷言與追蹤代碼。

進階技巧

1. `#` 字串化與 `##` 連接


#define STR(x) #x
#define CAT(a,b) a##b

STR(hello)   // "hello"
CAT(var, 1)  // var1

2. 多行宏 `do { ... } while(0)`


#define SAFE_FREE(p) \
    do { free(p); (p) = NULL; } while(0)

3. 檢查宏定義值而非僅存在性


#if DEBUG_LEVEL >= 2
    #define VERBOSE_LOG 1
#endif

4. 避免 `#if` 中使用未定義宏 (視為 0,但會警告)


#if defined(UNKNOWN_MACRO) && UNKNOWN_MACRO > 0  /* 安全寫法 */
#if UNKNOWN_MACRO > 0  /* 危險:未定義視為 0,GCC -Wundef 會警告 */

常見錯誤

錯誤修正
`#ifdef MACRO` 後無 `#endif`每個條件區塊必須配對 `#endif`
宏定義含分號 `#define N 10;`宏定義**不加分號**,使用處自動補上
`#if` 表達式含變數/函數呼叫條件編譯**僅支援編譯期常數表達式**
巢狀條件編譯縮進混亂保持一致縮進,IDE 可自動摺疊

結語

條件編譯是 C 語言**編譯期多態**的核心工具。善用衛兵、平台抽象、配置開關、版本矩陣、靜態斷言、除錯切換,能構建高度可配置、跨平台、零開銷抽象的代碼庫。原則:**業務邏輯用 `if`,編譯期配置用 `#if`,嚴禁混淆。**

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved