C 预处理器 ## 在什么情况下起作用,什么情况下不起作用?

nod*_*bog -5 c c-preprocessor

似乎有时与 ## 连接确实有效,有时则不起作用。

尽管它对于某些用途显然是至关重要的,但它是一个不可靠的功能。

使用##有一套明确的规则吗?

一个例子是:

file1.h
#define concat(a,b) a##b
#define BAR bar
extern int concat(fu,BAR) ();
Run Code Online (Sandbox Code Playgroud)

这里 concat 产生 fuBAR 而不是 fubar。

一个例子是:

file2.h
#define BAR bar
extern int fu##BAR ();
Run Code Online (Sandbox Code Playgroud)

这里 ## 会产生一个关于代码中杂散 ## 的错误。

zwo*_*wol 8

##遵守与您期望的规则不同的规则。这并不意味着它“不起作用”或“是一个不可靠的功能”,它只是意味着您必须以与您想象的不同的方式使用它。

\n

当你写的时候

\n
#define concat(a,b) a##b\n
Run Code Online (Sandbox Code Playgroud)\n

C 标准规定,在连接发生之前,参数a和不会进行宏扩展。b(N1570 \xc2\xa7 6.10.3.1。)这是与您不应用或宏参数时的行为的故意差异。###

\n

您可以通过双重扩展获得您想要的行为:

\n
#define concat(a,b) concat_(a,b)\n#define concat_(a,b) a##b\n
Run Code Online (Sandbox Code Playgroud)\n

根据此定义, 的参数在替换到宏体之前concat 会进行宏扩展,因为它们不被用作 的操作数##。然后每个参数都成为 的参数concat_,并且不会再次扩展,但这很好,因为扩展已经完成。

\n

当你写的时候

\n
#define BAR bar\nextern int fu##BAR ();\n
Run Code Online (Sandbox Code Playgroud)\n

C 标准表示##预处理器根本无法识别该运算符(因此会进入翻译阶段 7,其中它是一个不被任何语法规则接受的有效标记,因此会导致语法错误),因为它不是宏定义的一部分。(N1570 \xc2\xa7 6.10.3.3p2,3 \xe2\x80\x94 仅暗示;它表示当它出现在正在扩展的宏的替换列表中时##被识别。本节并没有说它是在任何其他时间都得到认可,并且该标准的其他部分在任何其他上下文中都没有给出任何含义。)##

\n