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

标签 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 是什么意思?

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

最佳答案

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

字段是:

# linenum filename [flags]
...

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

‘1’

This indicates the start of a new file.

‘2’

This indicates returning to a file (after having included another file).

‘3’

This indicates that the following text comes from a system header file, so certain warnings should be suppressed.

‘4’

This indicates that the following text should be treated as being wrapped in an implicit extern "C" block.

您会看到嵌套源自 #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>不是真正的文件。他们 是需要以某种方式表示的预处理器 token 的非文件源 在输出格式中,因此它们被视为好像它们是文件。称它们为伪文件

<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
    ...

关于c-preprocessor - 如何解释 C 预处理器输出中的#前缀行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49109904/

相关文章:

c - 在 if else 条件之间使用#ifdef

c - 指向结构的空指针,使用宏访问元素

c - 函数宏问题

c - 在 C 中使用 pthreads 时如何避免代码膨胀?

c++ - 对 C 宏的 undefined reference ,但在我定义它时会出现重新定义的错误

C 在不同的头文件中定义具有相同名称的宏?

c - C 项目的 IDE 中的预处理器感知代码导航

C 预处理器 #if 处理非整数常量

c - 如何使用宏或其他机制强制执行 API 定义?

c# - 什么时候在 .net 中使用预处理器指令?