C,C++宏中#与##的讲解

转载 2012年03月26日 12:19:11

宏中的#的功能是将其后面的宏参数进行字符串化操作(Stringizing operator),简单说就是在它引用的宏变量的左右各加上一个双引号。

如定义好#define STRING(x) #x之后,下面二条语句就等价。

       char *pChar = "hello";

       char *pChar = STRING(hello);

还有一个#@是加单引号(Charizing Operator)

#define makechar(x)  #@x

       char ch = makechar(b);与char ch = 'b';等价。

 

但有小问题要注意,宏中遇到#或##时就不会再展开宏中嵌套的宏了。什么意思了?比如使用char *pChar = STRING(__FILE__);虽然__FILE__本身也是一个宏,但编译器不会展开它,所以pChar将指向"__FILE__"而不是你要想的形如"D:\XXX.cpp"的源文件名称。因此要加一个中间转换宏,先将__FILE__解析成"D:\XXX.cpp"字符串。

定义如下所示二个宏:

#define _STRING(x) #x

#define STRING(x) _STRING(x)

再调用下面语句将输出带""的源文件路径

       char* pChar = STRING(__FILE__);

       printf("%s %s\n", pChar, __FILE__);

可以比较下STRING(__FILE__)与__FILE__的不同,前将带双引号,后一个没有双引号。

 

再讲下##的功能,它可以拼接符号(Token-pasting operator)。

MSDN上有个例子:

#define paster( n ) printf( "token"#n" = %d\n", token##n )

int token9 = 100;

再调用  paster(9);宏展开后token##n直接合并变成了token9。整个语句变成了

printf( "token""9"" = %d", token9 );

在C语言中字符串中的二个相连的双引号会被自动忽略,于是上句等同于

printf("token9 = %d", token9);。

即输出token9 = 100

 

 

有了上面的基础后再来看示例1

#define WIDEN2(x) L ## x

#define WIDEN(x) WIDEN2(x)

#define __WFILE__ WIDEN(__FILE__)

wchar_t *pwsz = __WFILE__;

第一个宏中的L是将ANSI字符串转化成unicode字符串。如:wchar_t *pStr = L"hello";

再来看wchar_t *pwsz = __WFILE__;

__WFILE__被首先展开成WIDEN(__FILE__),再展开成WIDEN2("__FILE__表示的字符串"),再拼接成 L"__FILE__表示的字符串" 即L"D:\XXX.cpp" 从而得到unicode字符串并取字符串地址赋值给pwsz指针。

 

在VC中_T(),TEXT ()也是用的这种技术。

在tchar.h头文件中可以找到:

#define _T(x)       __T(x)

#define __T(x)      L ## x

在winnt.h头文件中可以找到

#define TEXT(quote) __TEXT(quote)   // r_winnt

#define __TEXT(quote) L##quote      // r_winnt

因此不难理解为什么第三条语句会出错error C2065: 'LszText' : undeclared identifier

       wprintf(TEXT("%s %s\n"), _T("hello"), TEXT("hello"));

       char szText[] = "hello";

       wprintf(TEXT("%s %s\n"), _T(szText), TEXT(szText));

而将"hello"定义成宏后就能正确运行。

#define SZTEXT "hello"

       wprintf(TEXT("%s %s\n"), _T(SZTEXT), TEXT(SZTEXT));

注:由于VC6.0默认是ANSI编码,因此要先设置成unicode编码,在project菜单中选择Setting,再在C/C++标签对话框中的Category中选择Preprocessor。再地Preprocessor definitions编辑框中将_MBCS去掉,加上_UNICODE,UNICODE。

 

 

更多内容可以查考MSDN上对Preprocessor Operators的讲解

C/C++——浅谈函数宏应用优缺点

老的C语言程序员中有一种倾向,就是把很短的执行频繁的计算写成宏,而不是定义为函数。完成I / O的g e t c h a r,做字符测试的i s d i g i t都是得到官方认可的例子。人们这样做最...
  • u011832277
  • u011832277
  • 2013年08月26日 22:16
  • 1123

C/C++-技巧-宏

一、宏基础 宏在c/c++中扮演者比较重要的角色,虽然难以阅读和调试的缺点让宏的使用饱受诟病,但是在一些特殊的情况下,使用宏会带来极大的方便,甚至可以实现一些用其他方式无法实现的功能。 在c/c++程...
  • u011787119
  • u011787119
  • 2016年12月25日 18:59
  • 1915

【C/C++】定义无双引号的字符串宏

在某些特殊场合下,我们可能需要定义一个字符串宏,但又不能用双引号 比如像这样 #define HELLO hello world如果我们只是简单的展开HELLO,肯定会无法编译 std::cout 展...
  • aqtata
  • aqtata
  • 2013年11月13日 23:00
  • 2883

C,C++宏中#与##的讲解

文中__FILE__与示例1可以参见《使用ANSI C and Microsoft C++中常用的预定义宏》 宏中的#的功能是将其后面的宏参数进行字符串化操作(Stringizing opera...
  • hunnu_denny
  • hunnu_denny
  • 2013年12月10日 22:49
  • 469

C,C++宏中#与##的讲解(++)

文中__FILE__与示例1可以参见《使用ANSI C and Microsoft C++中常用的预定义宏》 宏中的#的功能是将其后面的宏参数进行字符串化操作(Stringizing ope...
  • business122
  • business122
  • 2014年08月07日 13:18
  • 576

C/C++语言中头文件的保护宏

保护宏就是C/C++头文件开始处的宏判断和宏定义,可以避免该头文件被多次加载执行而导致编译错误的宏。...
  • zzfenglin
  • zzfenglin
  • 2016年04月09日 11:36
  • 1753

C,C++ 宏中#与##的讲解

宏中的 #   的功能:    是将其后面的宏参数进行字符串化操作(Stringizing operator),简单说就是在它引用的宏变量的左右各加上一个双引号。 #@  :是加单引号(Charizi...
  • veronica001
  • veronica001
  • 2016年08月01日 16:56
  • 80

C++中宏和函数的区别

宏和函数写法以及调用方式,有很大的相似,但是他们却存在本质上的区别,函数调用时将实参表达式值求出来,然后赋值给形参,计算结果,而宏则是对实参表达式不做计算,直接替换。 eg: int fun(int ...
  • hsd2012
  • hsd2012
  • 2016年01月11日 20:45
  • 658

C++/C 宏定义(define)中#和## 的含义

#是字符串化的意思,出现在宏定义中的#是把跟在后面的参数转成一个字符串; ##是连接符号,把参数连接在一起。 例子: #include using namespace std; #define ...
  • fireblue1990
  • fireblue1990
  • 2017年02月17日 14:57
  • 338

C/C++ 宏定义中#、##、#@的区别

#表示:对应变量字符串化   ##表示:把宏参数名与宏定义代码序列中的标识符连接在一起,形成一个新的标识符 连接符#@:它将单字符标记符变换为单字符,即加单引号。例如: #define B(x)...
  • hellokandy
  • hellokandy
  • 2016年01月27日 11:26
  • 5214
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C,C++宏中#与##的讲解
举报原因:
原因补充:

(最多只允许输入30个字)