#define 中的「 # 運算符」和「 ## 運算符」

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