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

C語言預處理器詳解:宏定義、檔案包含、條件編譯與最佳實踐

     編輯:關於C

1. 概述

預處理器在編譯首遍掃描前執行,處理以 # 開頭的指令:#include、#define、#if 等。合理使用可提升可讀性、可移植性、模組化程度。

2. 宏定義

2.1 無參數宏


#define PI 3.14159
#define MAX(a,b) ((a)>(b)?(a):(b)) // 常見錯誤:缺外層括號
#define SQR(x) ((x)*(x))

規則:

  • 行尾不加分號(否則分號也會被替換)。
  • 宏名慣用全大寫。
  • 可巢狀:#define TWO_PI 2*PI。
  • 字串常數中的宏名不被替換:printf("PI"); 輸出 "PI"。
  • 可用 #undef 終止作用域。

2.2 有參數宏


#define MAX(a,b) ((a)>(b)?(a):(b))
#define PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__) // 可變參數 (C99)

關鍵差異:

特性宏函式
處理階段預處理(文字替換)編譯/連結
型別檢查無有
副作用參數多次求值單次求值
遞迴不支援支援
除錯難(無符號)易(可設中斷點)

經典陷阱


#define SQR(x) x*x
SQR(a+1)  // 展開 a+1*a+1 = a+a+1 錯誤
// 正確:
#define SQR(x) ((x)*(x))

#define DISP(expr) printf(#expr " = %d\n", expr)
DISP(x+y); // 輸出 "x+y = 3"
  • 宏名與參數列表間**不能有空格**:#define MAX (a,b) ... 會被視為無參宏。
  • 參數在字串化 # 或連接 ## 運算子中特殊處理。

3. 檔案包含 #include

  • #include <stdio.h>:系統標準路徑搜尋。
  • #include "my.h":先當前目錄,再系統路徑。
  • 防重複包含:
    #ifndef MY_H
    #define MY_H
    ...
    #endif

4. 條件編譯


#if DEBUG
    printf("debug: %d\n", x);
#elif TEST
    run_tests();
#else
    // release
#endif

#define OS_LINUX 1
#define OS_WIN 2
#if TARGET_OS == OS_LINUX
    // linux code
#endif

常用:
#ifdef MACRO / #ifndef MACRO、
#if defined(A) && !defined(B)、
#error "message" 強制編譯報錯、
#pragma message("info") 編譯器輸出訊息。

5. 預定義宏

  • __FILE__、__LINE__、__DATE__、__TIME__、__STDC__、__func__ (C99)。
  • 編譯器特定:__GNUC__, _MSC_VER 等。

6. 最佳實踐

  1. 常數用 const 或 enum 替代宏(有型別、可除錯)。
  2. 函式式宏改用 inline 函式(型別安全、單次求值)。
  3. 宏參數與整體**雙層括號**:#define MUL(a,b) ((a)*(b))。
  4. 避免宏副作用:SQR(i++) 會遞增兩次。
  5. 條件編譯隔離平台差異,而非大量 #ifdef 散落業務邏輯。
  6. 頭檔務必加防重複包含衛視。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved