【问题标题】:How does GCC process quotes in macro?GCC 如何处理宏中的引号?
【发布时间】:2013-06-28 04:53:39
【问题描述】:

我正在尝试测试 gcc 预处理器的宏扩展。

我写了以下代码:(仅用于测试)

#include <stdio.h>

#define QUOTE "
#define TMPL hello

int main(){
    printf(QUOTE TMPL QUOTE);
    return 0;
}

编译结果为:

$ gcc main.c -o main
main.c:3:15: warning: missing terminating " character
main.c: In function ‘main’:
main.c:7: error: missing terminating " character
main.c:7: error: missing terminating " character
main.c:7: error: ‘hello’ undeclared (first use in this function)
main.c:7: error: (Each undeclared identifier is reported only once
main.c:7: error: for each function it appears in.)
main.c:7: warning: format not a string literal and no format arguments
main.c:7: warning: format not a string literal and no format arguments
$ 

那我试着看看预处理后的结果

$ gcc -E main.c -o tmp.c
main.c:3:15: warning: missing terminating " character
$ 

虽然给出了警告,但它以某种方式在tmp.c 中生成了正确的预处理代码

int main(){
 printf(" hello ");
 return 0;
}

我编译器tmp.chello 打印正确。

我想知道为什么gcc -E 可以生成正确的代码,而使用gcc 直接编译失败。 gcc预处理器的两种方法有区别吗?

$ gcc --version
i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)

【问题讨论】:

  • 预处理器宏应该扩展为一系列词法分析器标记。所以你不能有像#define QUOTE "这样的宏;顺便说一句,你的 GCC 版本很旧,目前是 4.8
  • 你想用谷歌搜索“c preprocessor stringize”。

标签: c++ c gcc macros


【解决方案1】:

正如我所评论的,预处理器宏应该扩展为一系列词法分析器标记。使用 GCC 源代码,libcpp(负责预处理和标记化)正在生成一个标记流(不是纯字符)。最近的 GCC 4.8,在您的示例中以 gcc -Wall endyul.c -o endyl 运行时,提供了非常有用的诊断:

endyul.c:3:15: warning: missing terminating " character [enabled by default]
 #define QUOTE "
               ^
endyul.c: In function 'main':
endyul.c:7:5: error: missing terminating " character
     printf(QUOTE TMPL QUOTE);
     ^
endyul.c:7:5: error: missing terminating " character
endyul.c:4:14: error: 'hello' undeclared (first use in this function)
 #define TMPL hello
              ^
endyul.c:7:18: note: in expansion of macro 'TMPL'
     printf(QUOTE TMPL QUOTE);
                  ^
endyul.c:4:14: note: each undeclared identifier is reported only once for each function it appears in
 #define TMPL hello
              ^
endyul.c:7:18: note: in expansion of macro 'TMPL'
     printf(QUOTE TMPL QUOTE);
                 ^

您的 GCC 4.2 非常旧。您应该考虑升级它。

clang (3.3) 也给出了很好的诊断:

 clang -Wall endyul.c -o endyul   
 endyul.c:3:15: warning: missing terminating '"' character [-Winvalid-pp-token]
 #define QUOTE "
               ^
 endyul.c:7:12: error: expected expression
     printf(QUOTE TMPL QUOTE);
            ^
 endyul.c:3:15: note: expanded from macro 'QUOTE'
 1 warning and 1 error generated.

再次阅读CPP manual of GCC,尤其是StringificationConcatenation 的章节。

【讨论】:

  • 因为gcc -E 不生成代码,而是生成文本,它恰好看起来正确(但不是)。 C 预处理被定义为生成标记流(在上个世纪,C99 标准之前的旧编译器具有生成文本的预处理器;标准要求预处理应该生成标记,而不是纯文本)。
猜你喜欢
  • 2022-09-24
  • 1970-01-01
  • 1970-01-01
  • 2011-02-10
  • 1970-01-01
  • 2011-07-04
  • 1970-01-01
  • 2014-02-08
  • 2011-09-01
相关资源
最近更新 更多