C语言宏与单井号(#)和双井号(##)
C(和C++)中的宏(Macro)屬于編譯器預(yù)處理的范疇,屬于編譯器概念(而非運(yùn)行期概念)。下面對(duì)常遇到的宏的使用問(wèn)題做了簡(jiǎn)單總結(jié)。
關(guān)于#和##
在C語(yǔ)言的宏中,#的功能是將其后面的宏參數(shù)進(jìn)行字符串化操作(Stringfication),簡(jiǎn)單說(shuō)就是在對(duì)它所引用的宏變量通過(guò)替換后在其左右各加上一個(gè)雙引號(hào)。比如下面代碼中的宏:
#define WARN_IF(EXP) /do { if (EXP) /fprintf(stderr, "Warning:" #EXP "/n"); } /while(0)?那么在實(shí)際使用中會(huì)出現(xiàn)下面所示的替換過(guò)程:
WARN_IF(divider == 0);
被替換為:
do {if (divider == 0)fprintf(stderr, "Warning" "divider == 0" "/n"); } while(0);? ?這樣每次divider(除數(shù))為0的時(shí)候便會(huì)在標(biāo)準(zhǔn)錯(cuò)誤流上輸出一個(gè)提示信息。
? ?而##被稱(chēng)為連接符(concatenator),用來(lái)將兩個(gè)Token連接為一個(gè)Token。注意這里連接的對(duì)象是Token就行,而不一定是宏的變量。比如你要做一個(gè)菜單項(xiàng)命令名和函數(shù)指針組成的結(jié)構(gòu)體的數(shù)組,并且希望在函數(shù)名和菜單項(xiàng)命令名之間有直觀的、名字上的關(guān)系。那么下面的代碼就非常實(shí)用:
struct command {char *name;void (*function)(void); }; #define COMMAND(NAME) {NAME, NAME ## _command }? //然后你就用一些預(yù)先定義好的命令來(lái)方便的初始化一個(gè)command結(jié)構(gòu)的數(shù)組了:
struct command commands[] = {COMMAND(quit);COMMAND(help);... }? ? COMMAND宏在這里充當(dāng)一個(gè)代碼生成器的作用,這樣可以在一定程度上減少代碼密度,間接地也可以減少不留心所造成的錯(cuò)誤。我們還可以n個(gè)##符號(hào)鏈接n+1個(gè)Token,這個(gè)特性也是#符號(hào)所不具備的。比如:
#define LINK_MULTIPLE(a,b,c,d) a##_##b##_##c##_##d
typedef struct _record_type LINK_MULTIPLE(name, company, position, salary);
//這里這個(gè)語(yǔ)句將展開(kāi)為:
? //typedef struct _record_type name_company_position_salary;
? ##連接符號(hào)由兩個(gè)#號(hào)組成,其功能是在帶參數(shù)的宏定義中將兩個(gè)子串(token)連接起來(lái),從而形成一個(gè)新的子串。但它不可以是第一個(gè)或者最后一個(gè)子串。所謂的子串(token)就是指編譯器能夠識(shí)別的最下語(yǔ)法單元。
? #符是把傳遞過(guò)來(lái)的參數(shù)當(dāng)成字符串進(jìn)行替代。
? 下面看看它們是怎么工作的。這是MSDN上的一個(gè)例子。假設(shè)程序中已經(jīng)定義了這樣一個(gè)帶參數(shù)的宏:
#define paster(n) printf("token" #n "=%d", token##n)? 同時(shí)又定義了一個(gè)整形變量:int token9 = 9;
? 現(xiàn)在在主程序中以下面的方式調(diào)用這個(gè)宏: paster(9);
? ?那么在編譯時(shí),上面的這句話被擴(kuò)展為:printf("token" "9" "=%d", token9);
? ?注意到這個(gè)例子中,paster(9);中的這個(gè)"9"被原封不動(dòng)的當(dāng)成了一個(gè)字符串,與"token"連接在了一起,從而成為了token9。而#n也被"9"所替代。可想而知,上面程序運(yùn)行的結(jié)果就是在屏幕上打印出token9=9
?
總結(jié)
以上是生活随笔為你收集整理的C语言宏与单井号(#)和双井号(##)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 学习《apache源代码全景分析》之DS
- 下一篇: v8引擎详解