預處理(Preprocessing)發生在編譯器詞法掃描與語法分析之前,由預處理器自動處理所有以 # 開頭的指令。主要功能包括:
#define)#include)#ifdef/#if/#ifndef)#undef、#error、#pragma、#line 等善用預處理可提升程式碼可讀性、可移植性、模組化程度與除錯效率。
#define IDENTIFIER token-sequence
#undef 終止作用域。#define pint (int*) 導致 pint a, b; 展開為 int* a, b;(b 非指標)。應改用 typedef int* pint;。MAX(a++, b) 導致 a++ 執行多次)。#define MACRO(params) token-sequence-with-params
#define SQ(x) ((x)*(x))SQ(i++) 展開為 ((i++)*(i++)),i 遞增兩次;函數呼叫 Square(i++) 則只遞增一次。#define TEST(x) (x + TEST(x)) → 1 + TEST(1))。#將實參轉為字串常值:#define STR(x) #x → STR(abc) 展開為 "abc"。忽略前後空白,內部多空白壓縮為單空白。
##連接兩個 Token:#define PASTE(a,b) a##b → PASTE(var, 1) → var1。可連接多個 Token(a##_##b##_##c)。
若需先展開實參再套用 #/##,需引入中介宏:
#define _STR(s) #s
#define STR(s) _STR(s) // 先展開 s,再字串化
STR(INT_MAX) → "2147483647"
#define LOG(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
GCC 擴展支援 ##__VA_ARGS__ 自動移除前置逗號;亦可顯式命名 args...。
| 用途 | 宏定義 |
|---|---|
| 常數 | #define PI 3.1415926 |
| 最大/最小值 | #define MAX(a,b) (((a)>(b))?(a):(b)) |
| 結構體成員偏移 | #define OFFSET(type, member) ((int)&(((type*)0)->member)) |
| 陣列元素數 | #define ARR_SIZE(arr) (sizeof(arr)/sizeof((arr)[0])) |
| 字元轉大寫 | #define TOUPPER(c) ((c)>='a'&&(c)<='z'?(c)-0x20:(c)) |
| 除錯追蹤 | #define TRACE(fmt, ...) printf("[%s(%d)<%s>] " fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__) |
| 多語句安全包裹 | #define DO(...) do{__VA_ARGS__}while(0) |
| 泛型交換 | #define SWAP(t, x, y) do{ t tmp=*(y); *(y)=*(x); *(x)=tmp; }while(0) |
#include <header.h>:搜尋系統標準包含目錄。#include "header.h":先搜尋當前源檔目錄,再搜尋系統目錄。#ifdef MACRO
// MACRO 已定義時編譯
#else
// 未定義時編譯
#endif
#if EXPRESSION != 0
// 真
#elif OTHER_EXPR != 0
// 另一條件真
#else
// 假
#endif
EXPRESSION 必須為整數常數運算式(可含 defined(MACRO))。
#ifdef _WIN32 ... #else ... #endif#ifdef FEATURE_FLV ... #endif#ifdef DEBUG ... #endif,發布版移除 #define DEBUG 即可。#ifndef TEST ... #else i=0; #endif#ifndef __HEADER_H__
#define __HEADER_H__
// 宣告、定義
#endifextern int var;,單一 .c 檔 int var = 0; 定義,否則 C++ 連結器報重複定義錯誤。__LINE__:當前行號(整數)__FILE__:當前源檔名(字串)__DATE__:編譯日期 "Mmm dd yyyy"__TIME__:編譯時間 "hh:mm:ss"__STDC__:標準 C 合規性標誌(1 表合規)__func__(C99)、__FUNCTION__(GCC/MSVC)預處理器是 C 語言獨特的元編程層,掌握宏定義的替換語意、條件編譯的編譯期決策、檔案包含的依賴管理,能寫出更彈性、可移植、易維護的程式碼。切記:宏非函數,無型別、無作用域、無副作用控制,濫用易生難測 Bug,關鍵路徑優先考慮 inline 函數或 constexpr (C++)。