| 指令 | 用途 | 現代替代/補充 |
#define | 巨集定義 (物件/函數式) | constexpr, inline 變數, template |
#undef | 取消巨集 | 模組/命名空間隔離 |
#include | 檔案包含 | C++20 import (模組) |
#if #elif #else #endif | 條件編譯 (整數常數表達式) | if constexpr (C++17), 概念 |
#ifdef #ifndef | 巨集定義檢查 | 同上 |
#error | 編譯期報錯 | static_assert |
#pragma | 編譯器特定指令 | 標準屬性 [[...]] |
#line | 修改行號/檔名資訊 | 工具生成代碼用 |
#define 進階用法與陷阱
物件式巨集
#define MAX_SIZE 1024
#define PI 3.14159265358979323846
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x) // 兩層展開支援巨集參數字串化
函數式巨集 (慎用)
#define SQUARE(x) ((x)*(x)) // 括號保護參數與整體
// 陷阱:SQUARE(i++) → ((i++)*(i++)) 未定義行為
// 替代:constexpr auto square = [](auto x) { return x*x; };
變參巨集 (C99/C++11)
#define LOG(fmt, ...) fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, __VA_ARGS__)
#define LOG2(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) // C++20 __VA_OPT__(,) 處理空參數
關鍵規則
- 巨集無作用域,全域汙染風險極高
- 巨集不遵守型別系統,編譯器無法檢查參數型別
- 巨集文本替換,非語法結構,易產生難以診斷錯誤
- 能用 constexpr/const/inline/template 解決,絕不寫 #define
#include 搜尋路徑規則
#include // 系統標頭:編譯器內建路徑 + /I 指定路徑
#include "header" // 使用者標頭:當前檔案目錄 → /I 路徑 → 系統路徑
// 角括號 vs 雙引號:語意區別 > 搜尋順序差異
條件編譯實戰模式
平台/編譯器偵測
#if defined(_WIN32) || defined(_WIN64)
#define PLATFORM_WINDOWS 1
#elif defined(__linux__)
#define PLATFORM_LINUX 1
#elif defined(__APPLE__)
#define PLATFORM_MACOS 1
#endif
#if defined(_MSC_VER)
#define COMPILER_MSVC _MSC_VER
#elif defined(__clang__)
#define COMPILER_CLANG __clang_version__
#elif defined(__GNUC__)
#define COMPILER_GCC (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#endif
Header Guard (傳統) vs #pragma once
// 傳統 (可移植)
#ifndef MY_HEADER_H
#define MY_HEADER_H
// ...
#endif
// 現代 (所有主流編譯器支援,速度更快)
#pragma once
C++17 if constexpr 替代條件編譯
template
void process(T value) {
if constexpr (std::is_integral_v) {
// 整數邏輯
} else if constexpr (std::is_floating_point_v) {
// 浮點邏輯
} else {
static_assert(false, "Unsupported type");
}
}
// 編譯期分支,死代碼徹底消除,無巨集汙染
C++20 模組:終結 #include 時代
// math.ixx
export module math;
export constexpr double PI = 3.14159;
export int add(int a, int b) { return a + b; }
// main.cpp
import math;
import std; // 標準庫模組 (C++23)
int main() { std::cout << math::PI << ' ' << math::add(1,2); }
模組提供:隔離巨集、語意導入、更快建置、無 Header Guard 需求。
最佳實踐總結
- 常數用
constexpr/inline const
- 函數用
inline/constexpr/Lambda
- 條件編譯用
if constexpr/概念
- 平台抽象隔離在專用 Header,內部用巨集
- 新專案啟用 C++20 模組,漸進式替代
#include
- 編譯器警告
-Wmacro-redefined -Wundef 捕獲巨集問題
預處理器是 C++ 相容 C 的歷史包袱,現代 C++ (17/20/23) 提供了型別安全、模組化、編譯期計算的完整替代方案。新代碼應極小化巨集使用,擁抱標準化工具鏈。
- 上一篇文章: C++ clock() 計時函數詳解:精度限制、CPU 時間與現代替代方案
- 下一篇文章: C++ 記憶體邏輯區域劃分:堆疊、堆、靜態儲存區深度解析
Copyright ©
程式碼之家 All Rights Reserved