看到以下這段 code 真是一頭霧水:
#define __stringify_1(x...) #x
#define __stringify(x...)__stringify_1(x) // pre-scan
先說 #define 後面放 #x 的意思,
它是要把 #define 的參數展開成字串。
它是要把 #define 的參數展開成字串。
e.g. 在 #define _A(x) #x 下,_A(hahahaha) 會被展開成 "hahahaha"。
* 這種方法有個特殊的 term 叫 stringify。
那為什麼會有開頭那種寫法 "定兩次" 呢 ???
C 語言規則中,
stringify macro 不會去做 pre-scane ( 試圖先展開所有的 #define ),
stringify macro 不會去做 pre-scane ( 試圖先展開所有的 #define ),
也就是 #define 傳進來的參數如果是另外一個 #define,
編輯器不會去展開那個參數。
e.g. 如果今天我們只有寫這樣:
#define _A(x...) #x
#define CCC hahaha
那 printf(_A(CCC)); 會印出的是 CCC,
而不是我們可能想要的 hahaha。
而不是我們可能想要的 hahaha。
* 因為編譯器看到 _A 是個 stringify macro 所以不嘗試展開 CCC。
要使用 stringify macro 又想嘗試 pre-scan 的話,
就要用最上面那種雙層作法。
第二個 #define 因為不是 stringify macro 而會去 pre-scan,
pre-scane 完再丟給真正的 stringify macro 變成字串。
幹真是有夠神奇的定義啊 ...
stringification(中文不知道怎麼稱呼,暫稱他字串化吧),當macro所帶的參數前面加上"#"之後,這個參數就會被展成字串,這就是stringification。
如:
如:
#define WARN_IF(EXP) \ do { if (EXP) \ fprintf (stderr, "Warning: " #EXP "\n"); } \ while (0) WARN_IF (x == 0); -> do { if (x == 0) fprintf (stderr, "Warning: " "x == 0" "\n"); } while (0);
目前只有stringification,並沒有辦法轉成character。另外,stringification的優先權會高於argument expand。
如:
token concatenation或稱token pasting,是利用"##"將兩個token組成一個token,'##'被置於兩個token之間,如:
variadic其實就是不定參數的function-like macro,__VA_ARGS__代表"..."(即後面所有的參數),如:
cpp也可以使用name取代__VA_ARGS__,用法上只是在"..."前面加上name,"_VA_ARGS__"則用name取代即可,如:
來看另外一個例子
如:
#define xstr(s) str(s)
#define str(s) #s
#define foo 4
str (foo) -> "foo"
xstr (foo) -> xstr (4) -> str (4) -> "4"
token concatenation或稱token pasting,是利用"##"將兩個token組成一個token,'##'被置於兩個token之間,如:
#define COMMAND(name) {#name, name ## _command} struct command { char *name; void (*f)(void); } cmds[] = { COMMAND(quit), COMMAND(help), }; -> struct command { char *name; void (*f)(void); } cmds[] = { {"quit", quit_command}, {"help", help_command}, };
variadic其實就是不定參數的function-like macro,__VA_ARGS__代表"..."(即後面所有的參數),如:
#define eprintf(...) fprintf(stderr, __VA_ARGS__) eprintf("%s(#%d)\n", __FUNCTION__, __LINE__) -> fprintf(stderr, "%s(#%d)\n", __FUNCTION__, 7)
cpp也可以使用name取代__VA_ARGS__,用法上只是在"..."前面加上name,"_VA_ARGS__"則用name取代即可,如:
#define eprintf(args...) fprintf(stderr, args) eprintf("%s(#%d)\n", __FUNCTION__, __LINE__) -> fprintf(stderr, "%s(#%d)\n", __FUNCTION__, 7)
來看另外一個例子
#define eprintf(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) eprintf("hello\n"); -> fprintf(stderr, "hello\n", ); // error!!
這裡的問題就是如何將__VA_ARGS__前面的","在沒有參數帶入的時候刪除,答案就是"##"。
#define eprintf(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) eprintf("hello\n"); -> fprintf(stderr, "hello\n"); // correct!!
轉貼自http://nano-chicken.blogspot.tw/2010/05/gcc-441c-preprocessor-part-ii.html
全站熱搜
留言列表