宏參數(Arguments)的擴展


宏分為兩種,一種是 object-like 宏,比如:

#define STR "Hello, World!"

另一種是 function-like 宏,比如:

#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))

對於 function-like 宏,定義時的參數叫 Parameters,比如上面宏 MIN 的參數 X、Y,當調用時,傳遞的參數叫 Arguments。

宏參數 Arguments

當給宏傳遞參數 Arguments 時,可以不用全部傳遞,比如:

MIN(a, b)  ->  ((a) < (b) ? (a) : (b)) // 完全傳遞

MIN(, b) -> (() < (b) ? () : (b)) // 只傳遞后一個

MIN(a, ) -> ((a) < () ? (a) : ()) // 只傳遞前一個

MIN(,) -> (() < () ? () :()) // 這種允許

MIN(, ,) // 報錯,接收2個參數,傳遞了3個

MIN() // 報錯,接收2個參數,傳遞了1個

宏參數 Arguments 的擴展

當向宏中傳遞參數 Arguments 時,在參數替換到宏里面之前,首先要對參數 Arguments 進行完全的擴展,當參數擴展完畢之后,才將最終擴展的結果替換到宏里面,同時再對整個宏進行擴展。比如調用宏 MIN(MIN(a, b), c),那么首先第一個參數 MIN(a, b)要進行擴展,擴展的結果為 ((a) < (b) ? (a) : (b)),由於第2個參數 c 不用擴展,也就是第1步得到的擴展結果為:

MIN(((a) < (b) ? (a) : (b)), c)

接下來進行第2步擴展,得到的結果為:

((((a) < (b) ? (a) : (b))) < (c) ? (((a) < (b) ? (a) : (b))) : (c))

這樣做的一個好處是為了防止宏的嵌套調用,比如有下面一個宏定義:

#define f(x) x

如果有如下調用 f(f(1)),假設第一步不將參數 f(1) 完全展開,就會出現 f(f(1)) 被展開為 f(1),由於間接的自引用,宏不再繼續展開,此時得到的結果就為 f(1)。而有了2步擴展,第一步參數 f(1) 被擴展成 1,然后替換后繼續擴展,可以得到結果就是1。

自引用宏

一個宏在定義時,如果宏名出現在了宏定義中,那么就是一個自引用宏,比如:

#define foo (4 + foo)

如果調用這個宏 foo,按照上面兩步展開的過程,那么將會是一個無限循環的過程。首先 foo 展開為 (4 + foo),然后 (4 + foo) 中的 foo 繼續展開成 (4 + foo) 成為 (4 + (4 + foo)),如此繼續下去。但是實際上,對於自引用宏,只擴展1次,后面不會再做擴展,也就是說調用宏 foo,最終的擴展結果就是 (4 + foo)。

 

對於自引用宏的一種特殊情況就是間接自引用,比如有如下宏定義:

#define x (4 + y)
#define y (2 * x)

當調用宏 x 時,首先擴展為 (4 + y),然后對 y 進行擴展,結果為 (4 + (2 * x)),如果此時繼續對 x 進行擴展,那么就會無限遞歸,為了處理這種情況,擴展會在這一步終止,也就是最終結果是 (4 + (2 * x))。

當調用宏 y 時一樣,首先擴展為 (2 * x),然后對 x 進行擴展,結果為 (2 * (4 + y)),擴展到這一步也會停止。

參數 Arguments 有字符串化(#)和連接(##)操作

在宏擴展過程當中,當參數 Arguments 有字符串化(#)和連接操作(##)時,參數的擴展就沒有第1步。比如有下面宏定義:

#define AFTERX(x) X_ ## x
#define XAFTERX(x) AFTERX(x)
#define TABLESIZE 1024
#define BUFSIZE TABLESIZE

當調用 AFTERX(BUFSIZE) 時,由於參數 BUFSIZE 有連接操作(##),那么它就不會繼續擴展成 TABLESIZE,TABLESIZE 繼續擴展成1024,而是直接使用,也就是最終的擴展結果是 X_BUFSIZE,而不是 X_10。如果想要得到 X_10 的結果,需要做1次間接宏調用,重新定一個宏 XAFTERX 來調用宏 AFTERX,當調用宏 XAFTERX(BUFSIZE) 時,就會得到結果 X_10。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM