一、開始
前幾天看代碼,居然出來了“##”這個東東,不知道做什麼的,學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) #@ 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
請按任意鍵繼續. . .
三、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) #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"
四、Token-Pasting Operator (##)
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