2015-09-26 127 views
-1

最近我看到一些像這樣的代碼:瞭解宏擴展

​​

我測試的代碼,調用這樣的:

JOIN(Foo, 0); 
JOIN_(Foo, 1); 
JOIN__(Foo, 2); 

JOIN(Foo, JOIN(A,B)); 
JOIN_(Foo, JOIN(A,B)); 
JOIN__(Foo, JOIN(A,B)); 

宏擴展爲以下符號:

Foo0 
Foo1 
Foo2 
FooAB 
FooAB 
FooJOIN 

我得到了目的,它解決了不同的論點。在最後一種情況下,調用JOIN的任何變體顯然都不相同。但是這些宏如何擴展?爲什麼參數的行爲有所不同?

編輯:Here's文件

+0

我認爲,最後一個宏'JOIN __(Foo,JOIN(A,B));'應該擴展爲'FooJOIN(A,B)'而不只是'FooJOIN',請澄清。 –

+0

這是可能的。我得到'警告:函數'FooJOIN'的隱式聲明在C99'中是無效的,所以我真的不知道它得到了哪些參數。但是你的意思是有道理的 –

回答

1

EDIT

3.9.6參數預掃

宏參數是完全宏擴展它們是 代入宏體之前,除非它們被字符串化或與其他令牌粘貼 。替換之後,將再次掃描包括替換參數在內的整個宏體 ,宏將擴展爲 。結果是參數被掃描兩次以在其中擴展 宏調用。

調用其他宏的字符串化或連接的宏。如果 參數被字符串化或級聯,則不會發生預掃描。 如果您想要展開宏,然後將其展開或連接其擴展,可以通過使一個宏調用另一個執行串化或串聯的宏 來實現。

舉例來說,如果你有

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

然後AFTERX(BUFSIZE)擴展到X_BUFSIZE,並XAFTERX(BUFSIZE)擴展到X_1024。 (不X_TABLESIZE。預掃描總是做了完整的擴展。)

CASE1

#define JOIN__(lhs, rhs) lhs##rhs =>因爲它有一個標記粘貼操作者,它會連接這些宏參數那些不完全宏觀膨脹前取代。 - >這是一種糟糕的擴展方式,我們不知道的第一個地方,它將傳遞給它的參數是什麼,它不會等待它的擴展,而只是將它連接起來。

因此,當您撥打JOIN__(Foo, JOIN(A,B));時,它將不允許JOIN(A,B)展開,並將它連接到FOOJOIN(A,B)。

CASE2 現在,在另一方面, #define JOIN_(lhs, rhs) JOIN__(lhs, rhs) =>這裏,沒有標記粘貼操作,宏參數是完全宏擴展它們代入宏體之前。因此,它將允許lhs和rhs擴展並且用擴展參數JOIN__(FOO,AB)來調用,因此現在JOIN__具有令牌粘貼操作符,它將簡單地連接它的參數FOO和AB即FOOAB。這是做到這一點的適當方式。

CASE3 #define JOIN(lhs, rhs) JOIN_(lhs, rhs) =>與CASE2相同。

希望能解釋一下多級擴展範例背後的原因。

ORIGINAL 預處理運算符##提供了一種在宏擴展期間連接實際參數的方法。如果替換文本中的參數與##相鄰,則該參數將被實際參數替換,將刪除##和周圍的空白區域,並重新掃描結果。例如,宏粘貼連接它的兩個參數:

#define paste(front, back) front ## back 

so paste(name, 1) creates the token name1. 
+0

我知道令牌粘貼操作符。我在詢問這種多級擴展範例,而不是級聯 –

+0

@AndréFratelli:請查找「多級擴展範例」的更新答案。希望它解釋你在找什麼。 –

+0

真棒回答,真的很徹底。 –

1

##記號化操作不計算(宏展開)它的參數。函數式的宏擴展do然而,評估參數,這就是爲什麼你得到預期(評估)輸出的第一種情況。

技術上,宏JOIN_是不必要的,因爲在JOINlhsrhs擴大JOIN__時被評估。這將是足夠的:

#define JOIN(lhs, rhs) JOIN__(lhs, rhs) 
#define JOIN__(lhs, rhs) lhs##rhs 
+0

我真的找不到你錯了的情況,但爲什麼代碼會這樣寫呢? –

+0

請參閱我的編輯。我包含了原始代碼 –

+0

@AndréFratelli - 誰知道?人們會做一些奇怪的事情......但我認爲沒有任何理由將代碼編寫成這種方式。 – owacoder