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

时间:2018-03-05 11:51:50

标签: c-preprocessor

以下是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. # 1 "<built-in>" and # 1 "<command-line>"是什么意思?为什么它给了我内置和命令行的消息,这完全不相关?
  2. #1 "/usr/include/stdc-predef.h" 1 3 4是什么意思? 1 3 4是什么意思?
  3. 感谢。请注意,我知道预处理器将包含头文件。我想知道预处理输出的每个FIELD的含义。

1 个答案:

答案 0 :(得分:3)

预处理器输出的字段记录在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"
  • ...

阅读并不容易。

特殊的“文件名”<built-in><command-line>将永远突然出现 在类似的上下文中: -

# 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版本而异。

正如您所猜测的那样,<built-in><command-line>不是真正的文件。他们 是需要以某种方式表示的预处理程序令牌的非文件源 在输出格式中,所以它们被视为,好像它们是文件。称他们为伪文件

<built-in>是包含编译器内置宏的伪文件 定义。有关查看此伪文件内容的方法,请浏览到 GCC dump preprocessor defines

<command-line>当然是预处理器(通常是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
    ...