C巨集定義中##連線符與#符的含義
文章目錄
參考
http://lib.csdn.net/article/c/27630
note
不帶引數的巨集
巨集定義又稱為巨集代換、巨集替換,簡稱“巨集”。
格式:
#define 識別符號 字串
其中的識別符號就是所謂的符號常量,也稱為“巨集名”。
預處理(預編譯)工作也叫做巨集展開:將巨集名替換為字串
。
掌握"巨集"概念的關鍵是“換”。一切以換為前提、做任何事情之前先要換,準確理解之前就要“換”
。
即在對相關命令或語句的含義和功能作具體分析之前就要換:
例:
#define Pi 3.1415926
把程式中出現的Pi全部換成3.1415926
附加說明:
(1)巨集名一般用大寫
(2)使用巨集可提高程式的通用性和易讀性,減少不一致性,減少輸入錯誤和便於修改。例如:陣列大小常用巨集定義
(3)預處理是在編譯之前的處理,而編譯工作的任務之一就是語法檢查,預處理不做語法檢查。
(4)巨集定義末尾不加分號;
(5)巨集定義寫在函式的花括號外邊,作用域為其後的程式,通常在檔案的最開頭。
(6)可以用#undef命令終止巨集定義的作用域
(7)巨集定義允許巢狀
(8)字串( " " )中永遠不包含巨集
(9)巨集定義不分配記憶體,變數定義分配記憶體。
(10)巨集定義不存在型別問題,它的引數也是無型別的。
帶引數的巨集
除了一般的字串替換,還要做引數代換
格式:
#define巨集名(引數表) 字串
例如:#define S(a,b) a*b
area=S(3,2);第一步被換為area=a*b;
,第二步被換為area=3*2;
類似於函式呼叫,有一個啞實結合的過程:
(1)實參如果是表示式容易出問題
#define S(r) r*r
area=S(a+b);
第一步換為area=r*r
第二步被換為area=a+b*a+b;
正確的巨集定義是
#define S(r) ((r)*(r))
(2)巨集名和引數的括號間不能有空格
(3)巨集替換隻作替換,不做計算,不做表示式求解
(4)函式呼叫在編譯後程序執行時進行,並且分配記憶體。巨集替換在編譯前進行,不分配記憶體
(5)巨集的啞實結合不存在型別,也沒有型別轉換。
(6)巨集展開使源程式變長,函式呼叫不會
(7)巨集展開不佔執行時間,只佔編譯時間,函式呼叫佔執行時間(分配記憶體、保留現場、值傳遞、返回值)
應題重點
有參巨集定義中#的用法
#define STR(str) #str
#用於把巨集定義中的引數兩端加上字串的""
比如,這裡STR(my#name)會被替換成"my#name"
一般由任意字元都可以做形參,但以下情況會出錯:
STR())這樣,編譯器不會把“)”當成STR()的引數。
STR(,)同上,編譯器不會把“,”當成STR的引數。
STR(A,B)如果實參過多,則編譯器會把多餘的引數捨去。(VC++2008為例)
STR((A,B))會被解讀為實參為:(A,B),而不是被解讀為兩個實參,第一個是(A第二個是B)。
有參巨集定義中##的用法
它為巨集的擴充套件提供了一種連線實際變元的手段,如果替換文字中的引數被
##
相連,那麼引數就被實際變元替換,##
前後的空白被刪除,並對替換的結果進行掃描。
#define WIDE(str) L##str
則會將形參str的前面加上L
比如:WIDE(“abc”)就會被替換成L"abc"
其中的變化是: L##str L"abc"
注: 幹嘛加引號迷惑自己呢? 這樣來講吧:
define LINK(str) pre##str##after
eg: LINK(abc)
so we have : preabcafter
騷操作:
如果有#define FUN(a,b) vo##a##b()
那麼FUN(id ma,in)會被替換成void main()
實際的例子:
#define DFD_VERBOS(fmt, args...) do { \
if (DFD_DEBUG_CHECK(DFD_DBG_VBOSE)) { \
printf("[%s-%s]:<File:%s, Func:%s, Line:%d>\n" fmt, "DFD", "vbose", \
__FILE__, __FUNCTION__, __LINE__, ##args); \
} \
} while (0)