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

C 語言巨集 #define 完整用法總結:從基礎替換到條件編譯

     編輯:關於C語言

1. 簡單物件式巨集

#define IDENTIFIER replacement-list
// replacement-list 可為:數值、字串字面值、標點、運算子、識別字、關鍵字、字元常數、空

經典錯誤與修正

錯誤寫法展開結果問題正確寫法
#define N = 100int a[= 100];= 成為標記一部分#define N 100
#define N 100;int a[100;];分號被包含在替換文本中#define N 100
#define pin (int*)
pin a, b;
int* a, b;b 是 int 非指標typedef int* PIN;
PIN a, b;

創意用法 (不建議生產碼)


#define BEGIN {
#define END }
#define LOOP for(;;)
#define IT int

int main() BEGIN
    LOOP
        IT i = 0;
        break;
    END
END

2. 帶參數函數式巨集


#define MAX(x, y) ((x) > (y) ? (x) : (y))
#define IS_EVEN(n) ((n) % 2 == 0)

i = MAX(j + k, m - n);
// 安全展開:((j + k) > (m - n) ? (j + k) : (m - n))

if (IS_EVEN(i)) i++;
// 展開:if (((i) % 2 == 0)) i++;

關鍵規則

  • #define NAME(params) ... 中 NAME 與 ( 不能有空格,否則視為物件式巨集。
  • 參數在替換列表中完全展開後再代入 (遞迴展開),順序無關。
  • 參數加括號、整體加括號:防止運算子優先級錯誤。

3. 特殊運算子:# 字串化、## 連接


#define STR(x) #x          // 字串化
#define CAT(a, b) a##b     // 連接
#define CHAR(x) #@x        // 字元字面值化 (Microsoft 擴展,非標準)

STR(hello)    → "hello"
CAT(var, 1)   → var1
CHAR(1)       → '1'  (MSVC)

進階連接技巧


#define MAKE_FUNC(name) int func_##name(void) { return 0; }
MAKE_FUNC(init)  → int func_init(void) { return 0; }

#define DECLARE_ARRAY(type, name, size) type name##_arr[size]
DECLARE_ARRAY(int, buffer, 1024)  → int buffer_arr[1024];

4. 多行巨集與 do { ... } while(0) 慣用語


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

// 使用:SAFE_FREE(p);  // 結尾有分號,語法正確
// 若用 if/else 包裹會破壞 else 綁定;do-while(0) 解決此問題

5. 條件編譯:跨平台開發核心武器


#ifdef _WIN32
    #include 
    #define SLEEP(ms) Sleep(ms)
#elif defined(__linux__)
    #include 
    #define SLEEP(ms) usleep((ms)*1000)
#else
    #error "Unsupported platform"
#endif

// 編譯時指定:gcc -D_WIN32 ...

6. 取消巨集


#define DEBUG 1
// ... code ...
#undef DEBUG
// 之後 DEBUG 未定義

7. 預定義巨集 (標準 C)

巨集含義類型
__LINE__當前原始碼行號整數
__FILE__當前原始檔名稱字串
__DATE__編譯日期 (Mmm dd yyyy)字串
__TIME__編譯時間 (hh:mm:ss)字串
__STDC__符合標準 C 則為 1整數
__STDC_VERSION__C 版本 (199409L, 199901L, 201112L)整數
__cplusplusC++ 編譯器版本整數

實用除錯巨集範例


#define CHECK_ZERO(divisor) \
    do { \
        if ((divisor) == 0) { \
            fprintf(stderr, "*** DIVIDE BY ZERO at %s:%d ***\n", __FILE__, __LINE__); \
            abort(); \
        } \
    } while(0)

int div(int a, int b) {
    CHECK_ZERO(b);
    return a / b;
}

8. 巨集最佳實踐總結

  1. 巨集名稱全大寫,與變數/函數區分。
  2. 複雜邏輯優先用 inline 函數 (型別安全、除錯可見、避免副作用)。
  3. 巨集參數必須加括號,整體必須加括號。
  4. 避免巨集參數有副作用:MAX(i++, j++) 導致 i 增加兩次。
  5. 多行巨集使用 do { ... } while(0) 包裹。
  6. 條件編譯管理平台差異、功能開關、除錯碼。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved