2 回答

TA貢獻(xiàn)1982條經(jīng)驗(yàn) 獲得超2個(gè)贊
標(biāo)準(zhǔn)C預(yù)處理器
$?cat?xx.c#define?VARIABLE?3#define?PASTER(x,y)?x?##?_?##?y#define?EVALUATOR(x,y)??PASTER(x,y)#define?NAME(fun)?EVALUATOR(fun,?VARIABLE) extern?void?NAME(mine)(char?*x);$?gcc?-E?xx.c#?1?"xx.c"#?1?"<built-in>"#?1?"<command-line>"#?1?"xx.c"extern?void?mine_3(char?*x);$
兩級(jí)間接
為什么這需要兩個(gè)層次的間接。輕率的答案是,因?yàn)檫@是標(biāo)準(zhǔn)要求它工作的方式;你往往會(huì)發(fā)現(xiàn),你也需要與字符串操作符一樣的技巧。
C99標(biāo)準(zhǔn)第6.10.3節(jié)涵蓋“宏替換”,6.10.3.1涵蓋“參數(shù)替換”。
在確定了調(diào)用類似于函數(shù)的宏的參數(shù)之后,就會(huì)發(fā)生參數(shù)替換。替換列表中的參數(shù),除非前面有
#
或##
預(yù)處理令牌或后面是##
預(yù)處理令牌(見下文),在展開其中包含的所有宏后,將被相應(yīng)的參數(shù)替換。在被替換之前,每個(gè)參數(shù)的預(yù)處理標(biāo)記都會(huì)被宏完全替換,就好像它們構(gòu)成了預(yù)處理文件的其余部分一樣;沒有其他的預(yù)處理標(biāo)記可用。
在調(diào)用中NAME(mine)
,該參數(shù)為“my”;它被完全展開為“my”;然后將其替換為替換字符串:
EVALUATOR(mine,?VARIABLE)
現(xiàn)在,宏評(píng)估器被發(fā)現(xiàn),參數(shù)被隔離為‘my’和‘Variable’;后者隨后被完全展開為‘3’,并被替換成替換字符串:
PASTER(mine,?3)
其他規(guī)則(6.10.3.3‘#操作符’)涵蓋了這方面的操作:
如果在類似函數(shù)的宏的替換列表中,參數(shù)緊跟在
##
預(yù)處理令牌,將參數(shù)替換為相應(yīng)參數(shù)的預(yù)處理令牌序列;[.]對(duì)于類似對(duì)象的宏調(diào)用和類似函數(shù)的宏調(diào)用,在重新檢查替換列表以獲得要替換的更多宏名稱之前,
##
替換列表中的預(yù)處理令牌(不是從參數(shù)中刪除)被刪除,并將前面的預(yù)處理令牌與以下預(yù)處理令牌連接起來。
因此,替換列表包含x
緊隨其后##
還有##
緊隨其后y
因此,我們有:
mine?##?_?##?3
和消除##
任何一方的令牌和連接令牌將“my”與“_”和“3”組合在一起,從而產(chǎn)生如下結(jié)果:
mine_3
這是期望的結(jié)果。
如果我們看一下最初的問題,代碼(修改為使用‘my’而不是‘SomeFunction’):
#define?VARIABLE?3#define?NAME(fun)?fun?##?_?##?VARIABLENAME(mine)
關(guān)于名字的論點(diǎn)顯然是“我的”,而且已經(jīng)完全擴(kuò)展了。
按照6.10.3.3的規(guī)則,我們認(rèn)為:
mine?##?_?##?VARIABLE
當(dāng)##
運(yùn)算符被刪除,映射到:
mine_VARIABLE
和問題中的報(bào)道完全一樣。
傳統(tǒng)C預(yù)處理器
對(duì)于沒有令牌粘貼操作符的傳統(tǒng)C預(yù)處理程序,有什么方法可以做到嗎?
##
?
也許,也許不是-這取決于預(yù)處理程序。標(biāo)準(zhǔn)預(yù)處理器的優(yōu)點(diǎn)之一是它具有可靠工作的功能,而對(duì)于預(yù)標(biāo)準(zhǔn)的預(yù)處理器則有不同的實(shí)現(xiàn)。一個(gè)要求是,當(dāng)預(yù)處理器替換一個(gè)注釋時(shí),它不會(huì)像ANSI預(yù)處理器所要求的那樣生成一個(gè)空間。GCC(6.3.0)C預(yù)處理器滿足這一要求;XCode 8.2.1中的Clang預(yù)處理器不滿足這一要求。
當(dāng)它起作用時(shí),它就完成了(x-paste.c
):
#define?VARIABLE?3#define?PASTE2(x,y)?x/**/y#define?EVALUATOR(x,y)?PASTE2(PASTE2(x,_),y)#define?NAME(fun)?EVALUATOR(fun,VARIABLE) extern?void?NAME(mine)(char?*x);
請(qǐng)注意,在fun,
和VARIABLE
-這很重要,因?yàn)槿绻嬖?,則會(huì)將其復(fù)制到輸出中,而您的結(jié)果是mine_ 3
作為名稱,當(dāng)然,這在語(yǔ)法上是無效的。(現(xiàn)在,請(qǐng)把頭發(fā)還給我好嗎?)
GCC 6.3.0(跑步)cpp -traditional x-paste.c
),我明白:
#?1?"x-paste.c"#?1?"<built-in>"#?1?"<command-line>"#?1?"x-paste.c"extern?void?mine_3(char?*x);
使用XCode 8.2.1中的Clang,我得到:
#?1?"x-paste.c"#?1?"<built-in>"?1#?1?"<built-in>"?3#?329?"<built-in>"?3#?1?"<command?line>"?1#?1?"<built-in>"?2#?1?"x-paste.c" ?2extern?void?mine?_?3(char?*x);
那些空間破壞了一切。我注意到這兩個(gè)預(yù)處理器都是正確的;不同的預(yù)標(biāo)準(zhǔn)預(yù)處理器顯示了這兩種行為,這使得令牌粘貼在嘗試移植代碼時(shí)非常煩人和不可靠。標(biāo)準(zhǔn)##
符號(hào)從根本上簡(jiǎn)化了這一點(diǎn)。
也許還有其他方法可以做到這一點(diǎn)。然而,這是行不通的:
#define?VARIABLE?3#define?PASTER(x,y)?x/**/_/**/y#define?EVALUATOR(x,y)?PASTER(x,y)#define?NAME(fun)?EVALUATOR(fun,VARIABLE)extern? void?NAME(mine)(char?*x);
GCC:
#?1?"x-paste.c"#?1?"<built-in>"#?1?"<command-line>"#?1?"x-paste.c"extern?void?mine_VARIABLE(char?*x);
接近但沒有骰子。YMMV,當(dāng)然,取決于您使用的預(yù)標(biāo)準(zhǔn)預(yù)處理器。坦率地說,如果您被一個(gè)不合作的預(yù)處理器困住了,那么安排使用標(biāo)準(zhǔn)C預(yù)處理器代替預(yù)標(biāo)準(zhǔn)處理器(通常有一種適當(dāng)配置編譯器的方法)可能比花很多時(shí)間想出一種方法來完成這一工作要簡(jiǎn)單得多。

TA貢獻(xiàn)1828條經(jīng)驗(yàn) 獲得超6個(gè)贊
#define VARIABLE 3
#define NAME2(fun,suffix) fun ## _ ## suffix
#define NAME1(fun,suffix) NAME2(fun,suffix)
#define NAME(fun) NAME1(fun,VARIABLE)
int NAME(some_function)(int a);
老實(shí)說,你不想知道為什么會(huì)這樣。如果你知道為什么會(huì)起作用,你就會(huì)變成那個(gè)家伙在工作中,誰知道這類事情,每個(gè)人都會(huì)來問你問題。=)
編輯:如果你真的想知道它的工作原理,我很樂意發(fā)表一個(gè)解釋,假設(shè)沒有人比我強(qiáng)。
- 2 回答
- 0 關(guān)注
- 759 瀏覽
添加回答
舉報(bào)