如何解释 C 预处理器输出中的 # 前缀行?

Posted

技术标签:

【中文标题】如何解释 C 预处理器输出中的 # 前缀行?【英文标题】:How to interpret #-prefixed lines in C preprocessor output? 【发布时间】:2018-03-05 11:51:50 【问题描述】:

下面是hello.c的代码:

#include <stdio.h>

int
main (void)

  printf ("Hello, world!\n");
  return 0;

我使用命令gcc -E hello.c对其进行预处理,得到如下输出:

# 1 "hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 27 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 375 "/usr/include/features.h" 3 4
# 1 "/usr/include/sys/cdefs.h" 1 3 4
# 392 "/usr/include/sys/cdefs.h" 3 4
# 1 "/usr/include/bits/wordsize.h" 1 3 4
# 393 "/usr/include/sys/cdefs.h" 2 3 4
# 376 "/usr/include/features.h" 2 3 4
# 399 "/usr/include/features.h" 3 4
# 1 "/usr/include/gnu/stubs.h" 1 3 4
# 10 "/usr/include/gnu/stubs.h" 3 4
# 1 "/usr/include/gnu/stubs-64.h" 1 3 4
# 11 "/usr/include/gnu/stubs.h" 2 3 4
# 400 "/usr/include/features.h" 2 3 4
# 28 "/usr/include/stdio.h" 2 3 4





# 1 "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stddef.h" 1 3 4
# 212 "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stddef.h" 3 4
typedef long unsigned int size_t;
# 34 "/usr/include/stdio.h" 2 3 4

# 1 "/usr/include/bits/types.h" 1 3 4
# 27 "/usr/include/bits/types.h" 3 4
# 1 "/usr/include/bits/wordsize.h" 1 3 4
# 28 "/usr/include/bits/types.h" 2 3 4


typedef unsigned char __u_char;
typedef unsigned short int __u_short;
typedef unsigned int __u_int;
typedef unsigned long int __u_long;


typedef signed char __int8_t;
typedef unsigned char __uint8_t;
typedef signed short int __int16_t;
typedef unsigned short int __uint16_t;
typedef signed int __int32_t;
typedef unsigned int __uint32_t;

typedef signed long int __int64_t;
typedef unsigned long int __uint64_t;
////I omitted a lot in the following.

我知道这些信息可以用于调试符号。但我想知道每个FIELD的含义。但是,如果您能够回答以下问题,您的回答也将被接受。

    # 1 "&lt;built-in&gt;" and # 1 "&lt;command-line&gt;"是什么意思?为什么它给了我完全不相关的内置和命令行消息? #1 "/usr/include/stdc-predef.h" 1 3 4 是什么意思? 1 3 4 是什么意思?

谢谢。请注意,我知道预处理器将包含头文件。我想知道预处理输出的每个FIELD的含义。

【问题讨论】:

【参考方案1】:

预处理器输出的字段记录在9 Preprocessor Output GNU cpp 手册。

这些字段是:

# linenum filename [flags]
...

这样的一行意味着后面的内容 (...) 起源于这一行 编号linenum 在文件filename 中。可选的flags 是:-

‘1’

这表示一个新文件的开始。

‘2’

这表示返回到一个文件(在包含另一个文件之后)。

‘3’

这表明以下文本来自系统头文件,因此应禁止某些警告。

‘4’

这表示应将以下文本视为包含在隐式 extern "C" 块中。

您会看到嵌套来自#include 指令,例如

# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 27 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 375 "/usr/include/features.h" 3 4
# 1 "/usr/include/sys/cdefs.h" 1 3 4
...

告诉我们:

"hello.c" 的第 1 行开始一个新文件"/usr/include/stdio.h", 在第 27 行开始另一个新文件"/usr/include/features.h" 在第 #375 行开始另一个新文件"/usr/include/sys/cdefs.h" ...

读起来不容易。

特殊的“文件名”&lt;built-in&gt;&lt;command-line&gt; 总会出现 在类似的上下文中:-

# 1 "hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "hello.c"

在任何文件的预处理输出的顶部。详细信息可能因 GCC 版本而异。

如您所料,&lt;built-in&gt;&lt;command-line&gt; 不是真实文件。他们 是预处理器标记的非文件源,需要以某种方式表示 在输出格式中,因此它们被视为就像它们是文件。称它们为伪文件

&lt;built-in&gt; 是包含编译器内置宏的伪文件 定义。要查看此伪文件内容的方式,请浏览至 GCC dump preprocessor defines.

&lt;command-line&gt; 当然是预处理器(通常是 GCC)命令行, 被视为宏定义(可能还有非定义)的来源,例如

gcc ... -DFOO=1 -UBAR ...

所以你的例子:

# 1 "hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
...

表示这个过程:

开始阅读hello.c,然后 立即读取内置宏伪文件,然后 立即读取命令行伪文件,然后 立即读取预定义的宏文件/usr/include/stdc-predef.h 好像它被-include /usr/include/stdc-predef.h预先包含在命令行中,然后 继续并完成读取命令行伪文件,然后 继续阅读hello.c,然后 开始阅读/usr/include/stdio.h ...

【讨论】:

优秀的答案!我肯定会从中学到很多东西。谢谢!

以上是关于如何解释 C 预处理器输出中的 # 前缀行?的主要内容,如果未能解决你的问题,请参考以下文章

c++ 中的预处理器指令:以下代码的输出是啥?

覆盖 CPP 输出中的行标记文件名

XML 和 XSL 中的前缀命名空间处理由 XML 解析器返回错误

使用预处理器指令定义输出路径

GCC 转储预处理器定义

C预处理器