我们可以使用 C 预处理器 ## 运算符粘贴 3 个标记吗?

chq*_*lie 5 c concatenation language-lawyer c-preprocessor

似乎可以定义一个宏来连接 3 个标记为:

#define concat3(a,b,c) a##b##c
Run Code Online (Sandbox Code Playgroud)

中间令牌(例如由生成的令牌a##bb##c必须是有效的预处理器令牌)是否可以concat3(.,.,.)成功粘贴到所有符合要求的实现上?(1)


(1) 许多编译器支持..作为 case 范围的标记,这使其成为有效标记,但是 C 标准没有定义这个标记,那么concat3()宏会在不支持它的架构上失败吗?

sj9*_*126 4

在我看来,每个中间令牌都必须有效,否则就被认为是未定义的行为。我下面引用的部分来自C11标准,但C99和C20草案中的语言似乎是相同的。

第 6.10.3.3 节涵盖了运算符的实际解释##,并特别指的是连接前面和后面的标记,即它们是成对处理的。第 3 段有点令人困惑,因为它单独提到了地标替换(即,类似函数的宏的扩展,其中参数没有预处理标记),然后指定“如果结果不是有效的预处理标记,则行为是不明确的”。目前尚不清楚它是指地标案例还是所有串联。

然而,J.2 节将“预处理运算符的结果##不是有效的预处理标记”标识为无条件的未定义行为,所以我认为这可能有助于澄清我上面的观点。

另请注意,该标准规定运算符的求值顺序##未指定,因此每种可能的串联组合都必须有效。