似乎有时与 ## 连接确实有效,有时则不起作用。
尽管它对于某些用途显然是至关重要的,但它是一个不可靠的功能。
使用##有一套明确的规则吗?
一个例子是:
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)
这里 ## 会产生一个关于代码中杂散 ## 的错误。
##
遵守与您期望的规则不同的规则。这并不意味着它“不起作用”或“是一个不可靠的功能”,它只是意味着您必须以与您想象的不同的方式使用它。
当你写的时候
\n#define concat(a,b) a##b\n
Run Code Online (Sandbox Code Playgroud)\nC 标准规定,在连接发生之前,参数a
和不会进行宏扩展。b
(N1570 \xc2\xa7 6.10.3.1。)这是与您不应用或宏参数时的行为的故意差异。##
#
您可以通过双重扩展获得您想要的行为:
\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#define BAR bar\nextern int fu##BAR ();\n
Run Code Online (Sandbox Code Playgroud)\nC 标准表示##
预处理器根本无法识别该运算符(因此会进入翻译阶段 7,其中它是一个不被任何语法规则接受的有效标记,因此会导致语法错误),因为它不是宏定义的一部分。(N1570 \xc2\xa7 6.10.3.3p2,3 \xe2\x80\x94 仅暗示;它表示当它出现在正在扩展的宏的替换列表中时##
被识别。本节并没有说它是在任何其他时间都得到认可,并且该标准的其他部分在任何其他上下文中都没有给出任何含义。)##