#define 中的“ # 运算符”和“ ## 运算符”

隐身守侯 提交于 2020-03-02 08:02:58
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  
    这个定义中有三个语言符号:2、* 和 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库
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!