【问题标题】:apple cpp breaks macro-parameter pasting苹果 cpp 打破宏参数粘贴
【发布时间】:2020-11-22 05:56:10
【问题描述】:

编译下面的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" 确实是输出

但是,苹果的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 宏的第二个和第三个参数之间插入一个空格。

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

但是

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

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

谢谢

【问题讨论】:

  • # define ProjectRulesFile &lt;TopLevelProject.rules&gt; 替换 TopLevelProject 并根据需要包含文件。你需要用Concat3处理&lt;.rules&gt;吗?为什么?
  • a/**/b/**/c 不会像您认为的那样做。相当于a b c。我很惊讶它完全适用于 GCC 和香草 Clang。
  • @eric-postpischil 这是一个取自更大代码库(imake 配置文件集)的小示例,并且 Concat3 宏被多次调用,其中许多使用与我发布的相同语法。
  • @HolyBlackCat 我向你保证,最新的 plain-clang 仍然支持这一点。最新的apple-clang 的cpp,与plain-clang 版本号相同,不起作用。有没有办法通过其他策略获得相同的效果?
  • Concat3(a,b,c) a/**/b/**/c 是一种古老的、预先标准的、长期弃用的连接东西的方法。它不适用于任何现代产品。

标签: c++ c clang apple-developer


【解决方案1】:

Concat3(a,b,c) a/**/b/**/c 是一种古老的、预先标准的、长期被弃用的连接东西的方法。它通常不适用于任何现代(即 1990 年左右)。它可能专门用于将标题名称与一些编译器连接起来,因为这是一个实现定义的区域。

6.10.2/4 将&lt;&gt; 预处理令牌对或一对" 字符之间的一系列预处理令牌组合成单个标头名称预处理令牌的方法是实现-已定义。

用这种方法连接任何不是标题名称的东西是不可能的。

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

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

如果结果不是有效的预处理令牌(大多数标头名称不是),则不起作用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-18
    • 1970-01-01
    • 2018-10-25
    • 2015-12-21
    • 1970-01-01
    相关资源
    最近更新 更多