似乎有時與 ## 的連接確實有效,有時則無效。
這是一個不可靠的功能,即使它對于某些用途顯然是至關重要的。
使用## 是否有一套明確的規則?
一個例子是:
file1.h
#define concat(a,b) a##b
#define BAR bar
extern int concat(fu,BAR) ();
這里 concat 產生 fuBAR 而不是 fubar。
一個例子是:
file2.h
#define BAR bar
extern int fu##BAR ();
這里 ## 會在代碼中產生一個關于雜散 ## 的錯誤。
uj5u.com熱心網友回復:
##遵守與您期望的規則不同的規則。這并不意味著它“不起作用”或“是一個不可靠的功能”,它只意味著你必須以不同于你想象的方式使用它。
當你寫
#define concat(a,b) a##b
C 標準說在連接發生之前引數a和b不是宏擴展的。(N1570 § 6.10.3.1。)這是與您不應用或不應用宏引數時的行為的有意區別。###
您可以通過雙重擴展獲得您想要的行為:
#define concat(a,b) concat_(a,b)
#define concat_(a,b) a##b
使用此定義,引數 to在替換到宏主體之前concat 進行宏擴展,因為它們不被用作 的運算元##。然后每個引數都成為 的引數concat_,并且不會再次擴展,但這很好,因為擴展已經完成。
當你寫
#define BAR bar
extern int fu##BAR ();
C 標準說##前處理器根本無法識別運算子(因此進入翻譯階段 7,在該階段它是一個有效標記,不被任何語法規則接受,因此會導致語法錯誤),因為它是不是宏定義的一部分。(N1570 § 6.10.3.3p2,3 -僅暗示;它說當它出現在正在擴展的宏的替換串列中時##被識別。本節沒有說它在任何其他時間被識別,并且沒有其他標準的一部分在任何其他背景關系中給出了含義。)##
uj5u.com熱心網友回復:
使用## 是否有一套明確的規則?
C標準6.10.3.1:
在確定了呼叫類函式宏的引數后,將進行引數替換。替換串列中的引數,除非前面有 # 或 ## 預處理標記或后跟 ## 預處理標記(見下文),在其中包含的所有宏都已展開后,將替換為相應的引數。
基本上##連接發生在令牌擴展之前,因為結果##可能導致新的前處理器令牌。如果我們有這個:
#define concat(a,b) a##b
#define BAR bar
#define fuBAR "hello world"
然后puts(concat(fu,BAR));會列印"hello world"。
為了解決這個問題,您需要一個輔助宏來擴展前處理器標記,然后##再將它們傳遞給(or #) 所在的宏:
#define cc(a,b) a##b
#define concat(a,b) cc(a,b)
#define BAR bar
#define fuBAR "hello world"
#define fubar "fubar"
在此示例中a,andb被擴展為fu和barbeforecc被呼叫。所以現在puts(concat(fu,BAR));將列印“fubar”。
這里 ## 會在代碼中產生一個關于雜散 ## 的錯誤。
因為你只能在宏里面使用#and ,就這么簡單。不是宏。##extern int fu##BAR ();
uj5u.com熱心網友回復:
似乎有時串聯
##確實有效,有時則無效。
這就像說“有時乘法*確實有效,有時則無效”,然后提出諸如
int six = 5;
int product = six * 2; // results in 10 instead of 12
和
void f(int a, int b, int a * b); // rejected by the compiler
標記粘貼運算子的規范在 C17 語言規范的6.10.3.3 中介紹,您的第一個線索應該是這是 6.10.3 的一個小節,它描述了宏替換。不僅該部分的位置,而且其顯式文本都清楚地表明,令牌連接(僅)在宏替換的背景關系中發生:
對于類物件和類函式宏呼叫,在重新檢查替換串列以替換更多宏名稱之前,替換串列(不是來自引數)中的 ## 預處理標記的每個實體都將被洗掉,并且前面的預處理標記與以下預處理標記連接。
(C17 6.10.3.3/3)
沒有其他特殊處理的規范##,所以這就是它的全部范圍。
此外,
在確定了呼叫類函式宏的引數后,將進行引數替換。替換串列中的引數,除非前面有
#or##預處理標記或后跟 ## 預處理標記(見下文),在其中包含的所有宏都已展開后,將替換為相應的引數。
(C17 6.10.3.1/1;強調添加)
因此,在函式式宏引數是##(or #) 運算子的運算元的情況下,它們本身不是宏擴展的,盡管在重新掃描結果時可能會將連接的結果擴展為宏。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/448217.html
