1. 利用宏參數建立字符串:# 運算符
在類函數宏(function-like macro)的替換部分中,「#」符號用做一個預處理運算符,它能夠把語言符號(token)轉化爲字符串。例如,若是 x 是一個宏參量,那麼 #x 能夠把參數名轉化爲相應的字符串。該過程稱爲字符串化。
說明:類函數宏就是帶參數的宏。類函數宏的定義中,用圓括號括起來一個或多個參數,隨後這些參數出如今替換部分。
- #include <stdio.h>
- #define PSQR(x) printf("The square of " #x " is %d. /r/n", (x) * (x))
-
- int main(void)
- {
- int y = 5;
-
- PSQR(y);
- PSQR(2 + 4);
-
- return 0;
- }
-
- // 輸出:
- The square of y is 25. // 用 "y" 代替 #x
- The square of 2 + 4 is 36. // 用 "2 + 4" 代替 #x
- #define STRING2(x) #x
- #define STRING(x) STRING2(x)
-
- #define WQ wangqi
-
- #pragma message(STRING2(WQ)) // WQ(字符串)
- #pragma message(STRING(WQ)) // wangqi(字符串)
2. 預處理器的粘合劑:## 運算符
和 # 運算符同樣,## 運算符能夠用於類函數宏的替換部分。另外,## 運算符還可用於類對象宏(object-like macro)的替換部分。這個運算符把兩個語言符號組合成單個語言符號。例如,能夠定義以下宏:
宏調用 XNAME(4) 會展開成 x4 。
說明:類對象宏就是用來表明值的宏。如,#define PI 3.141593 中的PI。
- #include <stdio.h>
- #define XNAME(n) x ## n
- #define PRINT_XN(n) printf("x" #n " = %d/r/n", x ## n);
-
- int main(void)
- {
- int XNAME(1) = 14; // 變爲 int x1 = 14;
- int XNAME(2) = 20; // 變爲 int x2 = 20;
- PRINT_XN(1) // 變爲 printf("x1 = %d/r/n", x1);
- PRINT_XN(2) // 變爲 printf("x2 = %d/r/n", x2);
-
- return 0;
- }
-
- // 輸出:
- x1 = 14
- x2 = 20
- #define __T(x) L ## x
- #define _T(x) __T(x)
- #define _TEXT(x) __T(x)
-
- #define WQ "wangqi"
-
- #pragma message(__T(WQ)) // LWQ (標識符)
- wcout << _T(WQ); // wangqi(寬字節字符串)
3. 語言符號
從技術方面看,系統把宏的主體看成語言符號(token)類型字符串,而不是字符型字符串。C 預處理器中的語言符號是宏定義主體中的單獨的「詞(word)」。用空白字符把這些詞分開。例如:
這個定義中有一個語言符號:即序列 2*2 。可是:
這個定義中有三個語言符號:二、* 和 3 。
在處理主體中的多個空格時,字符型字符串和語言符號型字符串採用不一樣方法。考慮下面的定義:
把主體解釋爲字符型字符串時,預處理器用 4 * 8 替換 EIGHT 。也就是說,額外的空格也看成替換文本的一部分。可是,當把主體解釋爲語言符號類型時,預處理器用由單個空格分隔的三個語言符號,即 4 * 8 來替換 EIGHT 。 換句話說,用字符型字符串的觀點看,空格也是主體的一部分;而用語言符號字符串的觀點看,空格只是分隔主體中語言符號的符號。在實際應用中,有些 C 編譯器把宏主體看成字符串而非語言符號。在比這個實例更復雜的狀況下,字符與語言符號之間的差別纔有實際意義。
順便提一下,C 編譯器處理語言符號的方式比預處理器的處理方式更加複雜。編譯器能理解 C 的規則,不須要用空格來分隔語言符號。例如,C 編譯器把 2*2 看成三個語言符號。緣由是 C 編譯器認爲每一個 2 都是一個常量,而 * 是一個運算符。
摘自:《C Primer Plus(第五版)中文版》第16章 C預處理器和C庫