如何让Xcode 8 C预处理器忽略// #defines中的注释

mac*_*aut 5 c macos xcode c-preprocessor

C预处理器(cpp)似乎应该正确处理此代码:

#define A 1 // hello there

int foo[A];
Run Code Online (Sandbox Code Playgroud)

我希望A能用1.

发生的事情是A替换为1 // hello there,从而产生以下输出cpp -std=c99 test.c:

# 1 "test.c"

int foo[1 // hello there];
Run Code Online (Sandbox Code Playgroud)

哪个是无效的C并且无法编译.

我怎样才能cpp进行正确的更换?

关于编译器的注意事项:使用cppmac上最新的(8.2.1,2016年12月)Xcode,所以我怀疑它是由于过时的编译器.

Jon*_*ler 5

令我惊讶的是,我可以在Mac上重现问题(macOS Sierra 10.12.2; Apple LLVM version 8.0.0 (clang-800.0.42.1))使用/usr/bin/cpp哪个是XCode cpp- 但不使用GNU cpp(我只使用它调用cpp).

解决方法包括:

/usr/bin/gcc -E -std=c99 test.c
Run Code Online (Sandbox Code Playgroud)

这使用clang包装器gcc来运行C预处理器并正确处理版本.您可以添加一个-v选项,看看它运行的是什么; 我没有看到它cpp本身运行(它运行时clang -cc1 -E有很多其他信息).

您还可以使用:

clang -E -std=c99 test.c
Run Code Online (Sandbox Code Playgroud)

这实际上是一回事.

您也可以安装GCC并使用它而不是XCode.关于如何完成这项工作的答案存在问题(但这不适合胆小的人).

  • @Schwern:是的 - 我无法弄明白究竟发生了什么,但是`cpp`似乎有一个盲点.好奇 - 等同于一个bug.如果它不会尊重`-std = c99`,它应该抱怨它,而不是默默接受但忽略它. (2认同)

Sch*_*ern 2

请注意,这//不是有效的 C90 注释。它是在 C99 中引入的,因此请确保您的编译器和预处理器知道它们将使用 C99 标准。在许多情况下都是-std=c99. (这个问题经过编辑以明确这一点)


接下来是我不相信预处理器关心注释。从 C99 规范的 6.10 开始,显示了预处理器指令的语法,但没有任何地方提到注释......

ANSI C 标准明确指出应在 2.1.1.2“翻译阶段”第 3 阶段(C99 中的 5.1.1.2)中替换注释。(借鉴另一个答案)。

  1. 源文件被分解为预处理标记和空白字符序列(包括注释)。源文件不应以部分预处理标记或部分注释结尾。每条注释都被一个空格字符替换。保留换行符。是否保留除换行符之外的每个非空空白字符序列或将其替换为一个空格字符是实现定义的。

较旧的工具可能不遵循这一点,因为它们早于任何 C 标准,或者它们有错误,或者它们对标准的解释不同。他们可能保留了这些错误/怪癖以实现向后兼容性。用clang -E -std=c99vs进行测试/usr/bin/cpp -std=c99证实了这一点。尽管它们的底层是相同的编译器,但它们的行为不同。

$ /usr/bin/cpp --version
Apple LLVM version 8.0.0 (clang-800.0.42.1)
Target: x86_64-apple-darwin16.3.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

$ clang --version
Apple LLVM version 8.0.0 (clang-800.0.42.1)
Target: x86_64-apple-darwin16.3.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

$ ls -l /usr/bin/cpp
-rwxr-xr-x 1 root wheel 18240 Dec 10 01:04 /usr/bin/cpp
$ ls -l /usr/bin/clang
-rwxr-xr-x 1 root wheel 18240 Dec 10 01:04 /usr/bin/clang


$ /usr/bin/cpp -std=c99 test.c
# 1 "test.c"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 330 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "test.c" 2


int foo[1 // hello there];

$ /usr/bin/clang -E -std=c99 test.c
# 1 "test.c"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 331 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "test.c" 2


int foo[1];
Run Code Online (Sandbox Code Playgroud)

我怀疑调用 clang 会导致与行为不清楚时建立的/usr/bin/cpp原始行为的错误/怪癖兼容性。cpp

我想这里的教训是使用cc -E而不是cpp确保一致的行为。

  • http://stackoverflow.com/questions/1476892/poster-with-the-8-phases-of-translation-in-the-c-language/1479972#1479972,http://stackoverflow.com/questions/1510869/首先是 c 预处理器删除注释还是扩展宏 (2认同)