C 语言的编译过程
C 是一种编译型语言。与解释型语言相比,编译型语言提供更快的执行性能。编译 C 程序可以使用不同的编译器产品,例如 GCC、Clang、MSVC 等。本章将解释使用 GCC 编译器编译 C 程序时的后台运行情况。
编译 C 程序
由 1 和 0 位组成的二进制指令序列称为机器码。高级编程语言(例如 C、C++、Java 等)包含的关键字更接近人类语言(例如英语)。因此,用 C(或任何其他高级语言)编写的程序需要转换为等效的机器码。此过程称为编译。
请注意,机器码特定于硬件架构和操作系统。换句话说,在 Windows 操作系统的计算机上编译的某个 C 程序的机器码与在 Linux 操作系统的计算机上不兼容。因此,我们必须使用适合目标操作系统的编译器。

C 编译过程步骤
在本教程中,我们将使用 gcc(GNU 编译器集合)。 GNU 项目是由 Richard Stallman 发起的自由软件项目,旨在让开发者免费使用强大的工具。
gcc 编译器支持多种编程语言,包括 C 语言。为了使用它,我们需要安装与目标计算机兼容的版本。
编译过程分为四个不同的步骤 -
- 预处理
- 编译
- 汇编
- 链接
下图展示了编译过程。

示例
为了理解此过程,我们来看一下以下 C 语言源代码 (main.c) -
#include <stdio.h> int main(){ /* 我的第一个 C 语言程序 */ printf("Hello World! "); return 0; }
输出
运行代码并检查其输出 −
Hello World!
".c"是文件扩展名,通常表示该文件是用 C 语言编写的。第一行是预处理器指令 #include,指示编译器包含 stdio.h 头文件。/* 和 */ 中的文本是注释,用于文档编写。
该程序的入口点是 main() 函数。这意味着程序将从执行该函数块内的语句开始。此处,在给定的程序代码中,只有两条语句:一条在终端上打印"Hello World"语句,另一条语句指示程序在正确退出或结束时"返回 0"。因此,一旦我们编译完成,运行该程序时,我们只会看到"Hello World"这句话。
C 语言编译过程内部包含哪些内容?
为了使"main.c"代码可执行,我们需要输入命令"gcc main.c",编译过程将执行其包含的所有四个步骤。
步骤 1:预处理
预处理器执行以下操作:
- 它会删除源文件中的所有注释。
- 它会包含头文件的代码,头文件是一个扩展名为 .h 的文件,其中包含 C 函数声明和宏定义。
- 它会将所有宏(已命名的代码片段)替换为其值。
此步骤的输出将存储在一个文件中,其中包含扩展名为".i",因此它将位于"main.i"中。
为了在此步骤后立即停止编译,我们可以在源文件上使用 gcc 命令的"-E"选项,然后按 Enter 键。
gcc -E main.c
步骤 2:编译
编译器从预处理文件生成 IR 代码(中间表示),因此这将生成一个".s"文件。话虽如此,其他编译器可能会在此编译步骤生成汇编代码。
我们可以在此步骤后使用 gcc 命令中的"-S"选项停止,然后按 Enter。
gcc -S main.c
main.s 文件应该如下所示 -
.file "helloworld.c" .text .def __main; .scl 2; .type 32; .endef .section .rdata,"dr" .LC0: .ascii "Hello, World! \0" .text .globl main .def main; .scl 2; .type 32; .endef .seh_proc main main: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 subq $32, %rsp .seh_stackalloc 32 .seh_endprologue call __main leaq .LC0(%rip), %rcx call puts movl $0, %eax addq $32, %rsp popq %rbp ret .seh_endproc .ident "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0" .def puts; .scl 2; .type 32; .endef
步骤 3:汇编
汇编器获取 IR 代码并将其转换为目标代码,即机器语言代码(即二进制)。这将生成一个以".o"结尾的文件。
我们可以在 gcc 命令中使用选项"-c"并按 Enter 键来停止此步骤后的编译过程。
请注意,"main.o"文件不是文本文件,因此使用文本编辑器打开此文件时无法读取其内容。
步骤 4:链接
链接器会创建最终的二进制可执行文件。它将所有源文件的目标代码链接在一起。链接器知道在静态库或动态库中查找函数定义的位置。
静态库是链接器将所有用到的库函数复制到可执行文件的结果。动态库中的代码不会被完整复制,只有库的名称会被放入二进制文件中。
默认情况下,在第四步也是最后一步之后,即输入完整的"gcc main.c"命令而不使用任何选项时,编译器将创建一个名为"main.out"(在 Windows 系统中为"main.exe")的可执行程序,我们可以从命令行运行该程序。
我们也可以选择创建具有所需名称的可执行程序,方法是在 gcc 命令中添加"-o"选项,该选项位于我们正在编译的文件名之后。
gcc main.c -o hello.out
因此,如果您没有使用"-o""选项,那么现在我们可以输入"./hello.out"或者"./hello" 执行编译后的代码。输出将是"Hello World",随后会再次出现 shell 提示符。