預處理器在編譯前處理原始碼,執行宏替換、檔案包含、條件編譯。掌握 #define、#if/#ifdef、#/## 運算符、預定義宏,能構建靈活、可配置、跨平台的 C++ 代碼庫。
#define 定義宏與常量
#define PI 3.14159265358979323846
#define MAX(a,b) ((a) > (b) ? (a) : (b)) // 函數式宏:參數加括號、整體加括號
#define STR(x) #x // # 運算符:參數字串化
#define CONCAT(a,b) a##b // ## 運算符:符號連接
#define LOG(msg) std::cerr << __FILE__ << ":" << __LINE__ << " " << msg << std::endl
// 使用
std::cout << PI; // 3.14159...
std::cout << MAX(3,5); // 5
std::cout << STR(Hello); // "Hello"
int xy = 100; std::cout << CONCAT(x, y); // 100
LOG("Start"); // main.cpp:10 Start
條件編譯:#if / #ifdef / #ifndef / #elif / #else / #endif
// 1. 防重複包含 (Include Guard)
#ifndef MY_HEADER_H
#define MY_HEADER_H
// ... 宣告
#endif
// 2. 調試開關
#ifdef DEBUG
#define DBG(x) std::cerr << "[DEBUG] " << x << std::endl
#else
#define DBG(x) ((void)0)
#endif
// 3. 平台差異
#if defined(_WIN32) || defined(_WIN64)
#define PLATFORM_WINDOWS 1
#elif defined(__linux__)
#define PLATFORM_LINUX 1
#elif defined(__APPLE__)
#define PLATFORM_MACOS 1
#else
#error "Unsupported platform"
#endif
// 4. 版本控制
#if __cplusplus >= 202002L
#define HAS_CPP20 1
#else
#define HAS_CPP20 0
#endif
// 5. 註釋大段代碼
#if 0
// 暫時禁用的代碼
#endif
# 與 ## 運算符深度解析
| 運算符 | 名稱 | 功能 | 範例結果 |
# | 字串化 | 將宏參數轉為字串字面量 | STR(abc) → "abc" |
## | 符號連接 | 將兩個 Token 合併為單一 Token | CONCAT(var, 1) → var1 |
// 進階:自動生成 Getter/Setter
#define PROPERTY(type, name) \
private: type name##_; \
public: type get##name() const { return name##_; } \
public: void set##name(type value) { name##_ = value; }
class Person {
PROPERTY(std::string, Name)
PROPERTY(int, Age)
};
// 展開為:private: std::string Name_; public: std::string getName() { return Name_; } void setName(std::string v) { Name_ = v; } ...
標準預定義宏
| 宏 | 含義 | 範例值 |
__LINE__ | 當前行號 (int) | 42 |
__FILE__ | 當前檔案名 (const char*) | "main.cpp" |
__DATE__ | 編譯日期 (const char*) | "Oct 15 2025" |
__TIME__ | 編譯時間 (const char*) | "14:30:00" |
__cplusplus | C++ 標準版本 (long) | 202002L (C++20) |
__STDC_HOSTED__ | 宿主環境 (1) / 自由環境 (0) | 1 |
__func__ | 當前函數名 (C++11, 非宏) | "main" |
編譯器擴展預定義宏 (常用)
// GCC / Clang
#define __GNUC__ // GCC 主版本
#define __GNUC_MINOR__ // GCC 次版本
#define __clang__ // Clang 編譯器
#define __clang_major__
#define __clang_minor__
// MSVC
#define _MSC_VER // 1930 (VS 2022 17.3)
#define _MSC_FULL_VER
#define _MSVC_LANG // 202002L (C++20)
// 架構
#define __x86_64__ / __amd64__
#define __arm__ / __aarch64__
#define _M_IX86 / _M_X64 / _M_ARM64
最佳實踐與避坑
- 宏名大寫,避免與變數衝突。
- 參數加括號:
#define SQR(x) ((x)*(x)) 防 SQR(a+b) 展開錯誤。
- 多語句宏用 do-while(0):
#define MACRO() do { ... } while(0) 保證分號語法正確。
- 避免宏副作用:
MAX(i++, j++) 導致雙重遞增,改用 inline 函數或 constexpr。
- 條件編譯優於 #ifdef:
#if defined(DEBUG) && DEBUG_LEVEL > 2 更清晰。
- 現代 C++ 替代宏:
constexpr 常量、inline 函數、template 泛型、if constexpr 編譯期分支、source_location (C++20) 替代 __FILE__/__LINE__。