2011-06-28 117 views
16

這行是什麼意思?特別是,##是什麼意思?#define中的##是什麼意思?

 
#define ANALYZE(variable, flag)  ((Something.##variable) & (flag)) 

編輯:

一點點困惑依然。沒有##,結果如何?

+0

另請參閱:http://stackoverflow.com/questions/1597007/creating-c-macro-with-and-line-token-concatenation-with-positioning-macro – sharkin

回答

8

A little bit confused still. What will the result be without ##?

通常你不會注意到任何區別。但是的區別。假設Something的類型是:

struct X { int x; }; 
X Something; 

而且看:

int X::*p = &X::x; 
ANALYZE(x, flag) 
ANALYZE(*p, flag) 

沒有令牌連接符##,它擴展爲:

#define ANALYZE(variable, flag)  ((Something.variable) & (flag)) 

((Something. x) & (flag)) 
((Something. *p) & (flag)) // . and * are not concatenated to one token. syntax error! 

隨着令牌級聯它擴展爲:

#define ANALYZE(variable, flag)  ((Something.##variable) & (flag)) 

((Something.x) & (flag)) 
((Something.*p) & (flag)) // .* is a newly generated token, now it works! 

請務必記住,預處理器在預處理令牌上操作,而不是上的文本。所以如果你想連接兩個令牌,你必須明確地說出來。

10

##被稱爲令牌串聯,用於連接宏調用中的兩個令牌。

看到這個:

+3

實際上,它被稱爲令牌串聯。我不認爲IBM AIX C/C++編譯器的文檔是最好的參考! –

+0

@David:添加到我的答案。謝謝:-) – Nawaz

+0

@David:我沒有說IBM AIX C/C++編譯器是最好的參考。最好的參考就是標準本身。但是,我們仍然會提供其他網站的鏈接,包括在stackoverflow上的主題。 – Nawaz

3

根據維基百科

Token concatenation, also called token pasting, is one of the most subtle — and easy to abuse — features of the C macro preprocessor. Two arguments can be 'glued' together using ## preprocessor operator; this allows two tokens to be concatenated in the preprocessed code. This can be used to construct elaborate macros which act like a crude version of C++ templates.

檢查Token Concatenation

8

一個非常重要的部分是,此令牌級聯如下一些非常特殊的規則:

例如IBM doc:

  • 級聯發生在展開參數中的任何 宏之前。
  • 如果串聯的結果是 有效的宏名,它可用於即使 出現在它 通常不會提供其上下文 進一步更換。
  • 如果多於一個 ##操作員和/或# 操作者出現在宏定義的替換 列表,的運算符的計算的順序 不是 定義。

實例是也非常自我說明

#define ArgArg(x, y)   x##y 
#define ArgText(x)   x##TEXT 
#define TextArg(x)   TEXT##x 
#define TextText    TEXT##text 
#define Jitter    1 
#define bug     2 
#define Jitterbug    3 

隨着輸出:

ArgArg(lady, bug) "ladybug" 
ArgText(con) "conTEXT" 
TextArg(book) "TEXTbook" 
TextText "TEXTtext" 
ArgArg(Jitter, bug)  3 

Source是IBM文檔。可能因其他編譯器而異。

要在行:

它加到變量屬性的 「東西」。並且接受一個邏輯上結合的變量,如果Something.variable有一個標誌設置,那麼這個變量會給出結果。

所以我最後的評論和你的問題(可編譯使用g ++)的例子:

// this one fails with a compiler error 
// #define ANALYZE1(variable, flag)  ((Something.##variable) & (flag)) 
// this one will address Something.a (struct) 
#define ANALYZE2(variable, flag)  ((Something.variable) & (flag)) 
// this one will be Somethinga (global) 
#define ANALYZE3(variable, flag)  ((Something##variable) & (flag)) 
#include <iostream> 
using namespace std; 

struct something{ 
int a; 
}; 

int Somethinga = 0; 

int main() 
{ 
something Something; 
Something.a = 1; 

if (ANALYZE2(a,1)) 
    cout << "Something.a is 1" << endl; 
if (!ANALYZE3(a,1)) 
    cout << "Somethinga is 0" << endl; 
     return 1; 
}; 
+0

沒有'##'的結果會是什麼? –

+0

所以我的測試導致.gcc抱怨'a。## b'。 'a ## b'評估全球的權利。 'a.b'也可以評估結構實例a中的變量。 – fyr

+0

我添加了一個例子。 – fyr

2

讓我們考慮一個不同的例子:

考慮

#define MYMACRO(x,y) x##y 

沒有##,明確預處理器無法看到xy作爲單獨的令牌,可以嗎?

在你的榜樣,

#define ANALYZE(variable, flag)  ((Something.##variable) & (flag)) 

##根本就沒有必要因爲你沒有做任何新的標識符。事實上,編譯器問題「錯誤:粘貼」。「」和「變量」不提供有效的預處理令牌「

2

這不是您的問題的答案,只是一個CW帖子,有一些技巧可以幫助您探索預處理器你自己。

預處理步驟實際上是在編譯任何實際代碼之前執行的。換句話說,當編譯器開始構建代碼時,沒有任何#define語句或類似的東西被留下。

瞭解預處理程序對代碼做什麼的一個好方法是獲取預處理輸出並查看它。

這是如何做到這一點的Windows:

創建一個名爲TEST.CPP一個簡單的文件,並把它放在一個文件夾中,比如C:\ TEMP。 礦看起來像這樣:

#define dog_suffix(variable_name) variable_name##dog 

int main() 
{ 
    int dog_suffix(my_int) = 0; 
    char dog_suffix(my_char) = 'a'; 

    return 0; 
} 

不是很有用,但很簡單。打開Visual Studio命令提示符下,導航到該文件夾​​,然後運行命令行如下:

c:\temp>cl test.cpp /P 

所以,這是你的運行器(cl.exe),用你的文件編譯器,和/ P選項告訴編譯器將預處理輸出存儲到文件中。

現在在test.cpp旁邊的文件夾中,您會發現測試。我,這對我來說是這樣的:

#line 1 "test.cpp" 


int main() 
{ 
    int my_intdog = 0; 
    char my_chardog = 'a'; 

    return 0; 
} 

正如你所看到的,沒有的#define左側,只有它的代碼擴展成。