转载自http://pppboy.blog.163.com/blog/static/30203796201011501033268/
一、开始
前几天看代码,居然出来了“##”这个东东,不知道做什么的,学C++这么长时间了,居然。。。(太不给面子了)
本着“先行先赢”的实践学习精神和“为人民服务”的奉献精神,以网上找的很多资料为参考,美美地总结一下,激励自己,启发别人。
二、Charizing Operator (#@)
1.作用
字符化操作符。只能用于有传入参数的宏定义中,且必须置于宏定义体中的参数名前。作用,将传的单字符参数名转换成字符,以一对单引用括起来。
2.举例
1: // ---------------------------------------------------
2: // 说明:预处理操作符测试
3: // 时间:2010.12.1
4: // 工具:VS2008
5: // 作者:http://pppboy.blog.163.com
6: //---------------------------------------------------
7:8: #include "stdafx.h"
9: #include <iostream>10: using namespace std;11:12: //定义#@ 的宏
13: #define makechar(ch) #@ ch14:15: int main(int argc, char* argv[])16: {17: char a = makechar(b);
18: cout << a << endl;19:20: // warning C4305: “=”: 从“int”到“char”截断
21: a = makechar(2346);22: cout << a << endl;23:24: // warning C4305: “=”: 从“int”到“char”截断
25: a = makechar(-2);26: cout << a << endl;27:28: //error C2015: 常量中的字符太多
29: //a = makechar(23467);
30:31: system("pause");
32: return 0;
33: }34:
输出:
b62请按任意键继续. . .
三、Stringizing Operator (#)
1.作用
把宏参数变为一个字符串。是将宏定义中的传入参数名转换成用一对双引号括起来,字符串化操作符。其只能用于有传入参数的宏定义中,且必须置于宏定义体中的参数名前。
2.举例
1: // ---------------------------------------------------
2: // 说明:预处理操作符测试
3: // 时间:2010.12.4
4: // 工具:VS2008
5: // 作者:http://pppboy.blog.163.com
6: //---------------------------------------------------
7:8: #include "stdafx.h"
9: #include <iostream>10: using namespace std;11:12: #define make_string(str) #str13:14: int main(int argc, char* argv[])15: {16: //忽略传入参数名前面和后面的空格
17: cout << make_string(++abcd++) << endl;18: cout << make_string( abcd ) << endl;19:20: //当传入参数名间存在空格时,编译器将会自动连接各个子字符串
21: //用每个子字符串中只以一个空格连接,忽略其中多余一个的空格
22: cout << make_string(ab+++c++d) << endl;23: cout << make_string(ab c d) << endl;24:25: //某些形式的传入参数名中,若存在特殊字符,编译器会自动为其添加转义字符号'/'。
26: // "hello world /abc 'OK" -> /"hello world //abc /'OK/"
27: cout << make_string("hello world /abc 'OK") << endl;
28:29: //也会有不能解析的时候:error C2001: 常量中有换行符
30: //cout << make_string(abc/') << endl;
31:32: system("pause");
33: return 0;
34: }
输出:
1: ++abcd++2: abcd3: ab+++c++d4: ab c d5: "hello world /abc 'OK"
四、Token-Pasting Operator (##)
1.作用
符号连接操作符。将宏定义的多个形参成一个实际参数名。
2.示例
1: #include "stdafx.h"
2: #include <iostream>3: using namespace std;4:5: #define token_pasting(n) num##n6: #define token_pasting_space(n) num ## n7: int num9=99999;
8:9: int main(int argc, char* argv[])10: {11: cout << token_pasting(9) << endl;12:13: //中间有空格没有影响
14: cout << token_pasting_space(9) << endl;15:16: system("pause");
17: return 0;
18: }
输出:
9999999999
五、要注意的问题
凡宏定义里有用'#'或'##'的地方宏参数是不会再展开
示例(本例来源于网络,稍有修改)
1: #define f(a,b) a##b2: #define d(a) #a //以"#"开头的,直接替换,不展开
3: #define s(a) d(a) //非以"#"开头的,先展开,再替换
4:5: int main(int argc, char* argv[])6: {7: //因为d宏中的参数是另外一个宏,且带##,所以作为参数的宏不展开
8: cout << d(f(a,b)) << endl;9:10: //因为s宏中的参数是另外一个宏,但不带##,所以作为参数的宏先展开
11: cout << s(f(a,b)) << endl;12:13: system("pause");
14: return 0;
15: }16:17:
输出
f(a,b)ab
解决办法
用'#'或'##'的地方宏参数是不会再展开,所以解决办法就是再加一层宏,就是上面例子里的
#define s(a) d(a)
六、应用特例
弄的这么复杂,为什么要用这个东西呢?肯定是有它特别的用处。
//注:下面的例子来源于:http://hi.baidu.com/sodumeng/blog
1.合并匿名变量名
1: #define ___ANONYMOUS1(type, var, line) type var##line2: #define __ANONYMOUS0(type, line) ___ANONYMOUS1(type, _anonymous, line)3: #define ANONYMOUS(type) __ANONYMOUS0(type, __LINE__)4: //...
5: //使用:
6: ANONYMOUS(static int);7: //...
作用:在行号(这个匿名变量前加个名字)
1: 第一层: --> __ANONYMOUS0(static int, __LINE__);2: 第二层: --> ___ANONYMOUS1(static int, _anonymous, 70);3: 第三层: --> static int _anonymous70;
2.填充结构
1: #define FILL(a) {a, #a}2: enum IDD{OPEN, CLOSE};
3: typedef struct MSG{4: IDD id;5: const char * msg;6: }MSG;7:8: //...
9: //使用
10: MSG _msg[] = {FILL(OPEN), FILL(CLOSE)};11: //...
相当于
1: MSG _msg[] = {{OPEN, "OPEN"}, {CLOSE, "CLOSE"}};
3.记录文件名
1: #define _GET_FILE_NAME(f) #f2: #define GET_FILE_NAME(f) _GET_FILE_NAME(f)3: //...
4: //其实这个ms没有必要呀...权当学习吧...
5: static char FILE_NAME[] = GET_FILE_NAME(__FILE__);6: //...
4.得到一个数值类型所对应的字符串缓冲大小
1: #define _TYPE_BUF_SIZE(type) sizeof #type
2: #define TYPE_BUF_SIZE(type) _TYPE_BUF_SIZE(type)3: //...
4: //嗯,这个方法比较有创意
5: char buf[TYPE_BUF_SIZE(INT_MAX)];
6: //...
相当于
1: //--> char buf[_TYPE_BUF_SIZE(0x7fffffff)];
2: //--> char buf[sizeof "0x7fffffff"];
3: //这里相当于
4: char buf[11];
肯定还有其它的,懒的去找了,这些平时ms都用不到,不过可能写出一些很精彩的内容来。不过俺自己一般是想不出这种办法来,权当学习一下,看一些牛x源代码时也不至于太惭愧。
七、参考地址
总结时参考了很多网址,下面给出链接,引用内容所有权均为原作者所有。
我自己的内容随便修改引用:
http://hi.baidu.com/sodumeng/blog(忘了是哪一页了)
http://blog.youkuaiyun.com/waji2000/archive/2007/11/26/1902337.aspx
http://msdn.microsoft.com/en-us/library/91tt6dfs(VS.80).aspx
http://hi.baidu.com/linzhangkun/blog/item/714a61a2125fd8a5caefd0d6.html