前几天看代码,居然出来了“##”这个东东,不知道做什么的,学C++这么长时间了,居然。。。(太不给面子了)
本着“先行先赢”的实践学习精神和“为人民服务”的奉献精神,以网上找的很多资料为参考,美美地总结一下,激励自己,启发别人。
字符化操作符。只能用于有传入参数的宏定义中,且必须置于宏定义体中的参数名前。作用,将传的单字符参数名转换成字符,以一对单引用括起来。
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) #@ ch 14: 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:输出:
b 6 2 请按任意键继续. . .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) #str 13: 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: abcd 3: ab+++c++d 4: ab c d 5: "hello world /abc 'OK"1.作用
符号连接操作符。将宏定义的多个形参成一个实际参数名。
2.示例
1: #include "stdafx.h" 2: #include <iostream> 3: using namespace std; 4: 5: #define token_pasting(n) num##n 6: #define token_pasting_space(n) num ## n 7: 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: }输出:
99999 99999凡宏定义里有用'#'或'##'的地方宏参数是不会再展开
示例(本例来源于网络,稍有修改)
1: #define f(a,b) a##b 2: #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##line 2: #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) #f 2: #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.csdn.net/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
http://blog.chinaunix.net/u1/37538/showart_523947.html