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