apple cpp 破坏宏参数粘贴

apple cpp breaks macro-parameter pasting

编译如下test.cpp

# define TopLevelProject X11

#define Concat3(a,b,c) a/**/b/**/c

# define ProjectRulesFile Concat3(<,TopLevelProject,.rules>)

#include ProjectRulesFile

cpp -I。 test.cpp

预期的行为是生成包含语句

# 1 "test.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test.cpp"
# 10 "test.cpp"
# 1 "./X11.rules" 1
# 11 "test.cpp" 2



# 1 "./X11.rules" 1
# 15 "test.cpp" 2

注意这行 "./X11.rules" 确实是输出

然而,apple 的 clang cpp 给出了输出

# 1 "test.cpp"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 361 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "test.cpp" 2


test.cpp:7:10: fatal error: ' X11 .rules' file not found
#include ProjectRulesFile
         ^~~~~~~~~~~~~~~~
test.cpp:5:35: note: expanded from macro 'ProjectRulesFile'
# define ProjectRulesFile       Concat3(<,TopLevelProject,.rules>)
                                ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:3:24: note: expanded from macro 'Concat3'
#define Concat3(a,b,c) a/**/b/**/c
                       ^~~~~~~~~~~

1 error generated.

注意格式错误的文件名 ' X11 .rules'

Apple的cpp在Concat3宏的第一个参数前插入一个space,在第二个和第三个参数之间插入一个

所有版本的 gcc、clang 和 msdev 工具都执行正确的文本替换。

但是

苹果的所有版本的cpp,比如xcode发布的,都有这个bug。

是否可以使用某种宏参数连接方案来编写 Concat3 宏,以便它在苹果的 cpp 下工作?

谢谢

Concat3(a,b,c) a/**/b/**/c 是一种古老的、pre-standard、长期弃用的连接方法。它通常不适用于任何现代(即 1990 年左右)。它 可能 专门用于将 header 名称与 某些 编译器连接起来,因为那是一个 implementation-defined 区域。

6.10.2/4 The method by which a sequence of preprocessing tokens between a < and a > preprocessing token pair or a pair of " characters is combined into a single header name preprocessing token is implementation-defined.

无法使用此方法连接任何非 header 名称的内容。

没有标准的方法来连接适用于所有编译器的 header 名称。标准技巧

#define CAT(a,b) CAT2(a,b)
#define CAT2(a,b) a ## b

如果结果不是有效的预处理标记则不起作用,大多数 header 名称都不是。