#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
// 使用時傳入具體參數
if (KEYDOWN(VK_UP)) { /* ... */ }
很多初學者認為 #define KEYDOWN(vk_code) 中的 vk_code 是固定字面量,實際上 宏參數是佔位符,預處理器會進行「符號替換」。
KEYDOWN(VK_UP)VK_UPvk_code 替換為 VK_UP((GetAsyncKeyState(VK_UP) & 0x8000) ? 1 : 0)| 特性 | 宏 (#define) | 函數 |
|---|---|---|
| 處理階段 | 預處理期(編譯前) | 編譯期/連結期 |
| 參數機制 | 文本替換(無類型檢查) | 值傳遞/引用傳遞(強類型) |
| 偵錯可見性 | 不可見(展開後無宏名) | 可見(保留函數符號) |
| 適用場景 | 簡單表達式、常數、條件編譯 | 複雜邏輯、需類型安全場合 |
#define SQUARE(x) ((x) * (x))
int i = 5;
int result = SQUARE(i++); // 展開為 ((i++) * (i++)) → 結果 30,i 變 7!
修正: 改用 inline 函數或確保參數無副作用。
#define ADD(a, b) a + b
int x = ADD(1, 2) * 3; // 展開 1 + 2 * 3 = 7,非預期 9
// 修正:#define ADD(a, b) ((a) + (b))
#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
// ↑ ↑ ↑ ↑ 關鍵括號
// C++17 constexpr 函數:類型安全、可偵錯、零開銷
constexpr bool isKeyDown(int vk_code) noexcept {
return (GetAsyncKeyState(vk_code) & 0x8000) != 0;
}
// 使用
if (isKeyDown(VK_UP)) { /* ... */ }
總結: 宏參數替換是純文本操作,KEYDOWN(vk_code) 中的 vk_code 只是佔位符,調用時傳入任何合法表達式皆可替換。理解預處理機制是掌握 C/C++ 元編程的基石。