编译器
在 C 预处理器包含所有头文件并扩展所有宏之后,编译器可以编译该程序。它通过将 C 源代码转换为目标代码文件来实现,目标代码文件是以 .o
结尾的文件,其中包含源代码的二进制版本。但是,对象代码不能直接执行。为了生成可执行文件,你还必须为文件中的所有库函数添加代码(这与包含声明不同,这是 #include
的作用)。这是链接器的工作。
通常,如何调用 C 编译器的确切顺序在很大程度上取决于你使用的系统。这里我们使用的是 GCC 编译器,但需要注意的是存在更多的编译器:
% gcc -Wall -c foo.c
%
是操作系统的命令提示符。这告诉编译器在文件 foo.c
上运行预处理器,然后将其编译到目标代码文件 foo.o
中。-c
选项意味着将源代码文件编译为目标文件,但不调用链接器。此选项 -c
可在 POSIX 系统上使用,例如 Linux 或 macOS; 其他系统可能使用不同的语法。
如果你的整个程序都在一个源代码文件中,你可以改为:
% gcc -Wall foo.c -o foo
这告诉编译器在 foo.c
上运行预处理器,编译它然后链接它以创建一个名为 foo
的可执行文件。-o
选项表明该行的下一个单词是二进制可执行文件(程序)的名称。如果你没有指定 -o
,(如果你只输入 gcc foo.c
),由于历史原因,可执行文件将被命名为 a.out
。
通常,将 .c
文件转换为可执行文件时,编译器会执行以下四个步骤:
- 预处理 - 在
.c
文件中以文本方式展开#include
指令和#define
宏 - 编译 - 将程序转换为程序集(你可以通过添加
-S
选项在此步骤停止编译器) - assembly - 将程序集转换为机器代码
- linkage - 将目标代码链接到外部库以创建可执行文件
另请注意,我们使用的编译器的名称是 GCC,它代表“GNU C 编译器”和“GNU 编译器集合”,具体取决于上下文。存在其他 C 编译器。对于类 Unix 操作系统,其中许多都有名称 cc
,用于“C 编译器”,它通常是一些其他编译器的符号链接。在 Linux 系统上,cc
通常是 GCC 的别名。在 macOS 或 OS-X 上,它指向 clang。
POSIX 标准目前要求 c99
作为 C 编译器的名称 - 它默认支持 C99 标准。早期版本的 POSIX 强制要求 c89
作为编译器。POSIX 还要求此编译器理解我们上面使用的 -c
和 -o
选项。
注意: gcc
示例中的 -Wall
选项告诉编译器打印有关可疑结构的警告,强烈建议这样做。添加其他警告选项也是一个好主意,例如 -Wextra
。