C 語言編譯首輪掃描前,預處理器會處理所有以 # 開頭的指令。這純粹是文字層面的替換、包含、刪除,不涉及語法分析。ANSI C 規範 11 種預處理指令,本文聚焦最常用的 5 類並給出實戰範例。
#define 巨集定義#define 宏名 替換文本
預處理器將原始碼中所有「宏名」替換為「替換文本」(不含尾隨分號)。
| 類型 | 範例 | 說明 |
|---|---|---|
| 符號常數 | #define MAX_SIZE 100 | 替換字面值,便於維護 |
| 布林模擬 | #define TRUE 1 | C89 無 bool 類型 |
| 帶參數巨集 | #define MAX(x,y) ((x)>(y)?(x):(y)) | 參數需加括號,整體加括號 |
| 多行巨集 | #define PRINT_LOG(msg) \\\n do { printf("%s", msg); } while(0) | 反斜線換行,do-while(0) 保證語句完整性 |
MAX(i++, j++) 導致 i++ 執行兩次 → 改用 inline 函數(C99)或極度小心MAX_BUFFER_SIZE),避免與變數衝突config.h#error 編譯期錯誤強制編譯器停止並輸出訊息,用於條件編譯檢查:
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
#error "需要 C99 標準編譯器"
#endif
#include 檔案包含| 語法 | 搜尋順序 | 適用場景 |
|---|---|---|
#include <stdio.h> | 系統標準路徑(INCLUDE 環境變數/IDE 設定) | 標準庫、系統頭檔 |
#include "myheader.h" | 當前原始檔目錄 → 系統路徑 | 專案自訂頭檔 |
// myheader.h
#ifndef MYHEADER_H
#define MYHEADER_H
// 內容...
#endif
或使用 #pragma once(非標準但廣泛支援)。
#if、#else、#elif、#endif#if 常數表達式
// 程式碼段 A
#elif 另一常數表達式
// 程式碼段 B
#else
// 程式碼段 C
#endif
#if DEBUG_LEVEL > 2 包含詳細日誌#ifdef _WIN32 / #elif defined(__linux__)#if VERSION >= 2 啟用新功能#ifdef/#ifndef 簡寫#ifdef DEBUG ≡ #if defined(DEBUG)
#ifndef RELEASE ≡ #if !defined(RELEASE)
#undef 取消巨集定義限制巨集作用域,避免汙染後續編譯單元:
#define TEMP_MACRO 123
// 使用 TEMP_MACRO...
#undef TEMP_MACRO
// 此處 TEMP_MACRO 不再生效
| 指令 | 用途 |
|---|---|
#line | 修改 __LINE__/__FILE__ 預定義巨集,除錯工具生成代碼用 |
#pragma | 編譯器特定指令(對齊、優化、警告控制),不可移植 |
Turbo C:Alt+C → Preprocess to file 產生 .i 檔
GCC/Clang:gcc -E source.c > source.i
MSVC:cl /E source.c
查看 .i 檔可驗證巨集展開、條件編譯結果、頭檔包含順序。
預處理器雖然「不識語法」,卻是 C 語言靈活性、可移植性、條件編譯的基石。掌握 #define 安全用法、#include 搜尋機制、條件編譯模式,並善用 .i 檔驗證,能讓你駕馭大型專案配置、跨平台編譯與除錯開關切換。