參考資料:《C Primer Plus》
1. 字符映射
在C語言預處理的第一步,預處理器會對源代碼中的字符作映射處理,若沒有特殊要求,這一步一般不會改變源代碼的字符。如果程序員需要,字符映射可以將一些擴展的三元字符轉換為源字符,例如??=轉換為#、??/轉換為\等等。之所以這樣做是因為不是所有的鍵盤都能打出#這樣的符號,所以通過映射規則的約定來進行處理。
2. '\\'+'\n'
預處理器在連續讀到反斜線符和換行符時會將這兩個字符刪除,從而將當前所在的物理行和下一個物理行合並為一個邏輯行。在定義一些比較復雜的宏或字符串時用這個方法可以方便換行閱讀,例如
printf("That's wond\ erful!\n");
等價於
printf("That's wonderful!\n");
3. 注釋
預處理器將注釋替換為一個空格字符。
4. 預處理指令
預處理器會將所有以#開頭,以換行符結束的字符串作為一條預處理指令,但這個規則不受'\\'+'\n'組合的影響,因此預處理指令可以多行表示。
4.1 #define-basic
#define指令可以實現字符串替換,前後分為三個部分,分別是#define、宏、替換列表。宏可以分為類對象宏或類函數宏,宏的命名方式和變量標識符一樣,可以由字母、數字、下劃線組成但首字符不能是數字。如果宏中出現了圓括號,那麼將作為類函數宏處理,否則認為是類對象宏。例如
#define PX printf("X is %d.\n",x) #define PR(Z) printf("The result is %d.\n", Z) int main() { int x=0; PX; PR(x); return 0; }
預處理後的結果為
int main() { int x=0; printf("x is %d",x); printf("The result is %d.\n",x); return 0; }
#define支持重定義,代碼在前面使用#define定義了一個宏MACRO之後,可以在後面再使用#define更改MACRO的定義。
4.2 #define-##、#、...、__VA_ARGS__
##可以實現標識符的粘合。例如定義#define INT(name) x##name,則INT(1)將轉換為x1,之所以這樣是因為#define的文本替換是以標識符為單位的,如果直接定義#define INT(name) xname,由於xname與name不是同一個標識符,INT(1)將不能轉換為x1。
#可以實現標識符的字符串化,這個功能配合字符串的連接特性可以解決對字符串進行文本替換的問題,之所以這樣是因為#define不對字符串的內容進行文本替換。例如#define PSQR(X) printf("The square of X is %d.\n",((X)*(X)));則替換列表中的第一個X將不會被替換。解決的辦法是寫為#define PSQRprintf("The square of #X " is %d.\n",((X)*(X)));
...和__VA_ARGS__可以實現可變參數宏,例如定義#define PR(...) printf(__VA_ARGS__),則使用PR即可代替printf函數。注意...只能作為最後一個參數,#define FPR(X,...,Y) fprintf(X,__VA_ARGS__,Y)是錯誤的。