C语言经典的 “hello world ” 程序,伴随着每个程序员一起步入编程世界的大门。从编写、编译到运行,看到屏幕上输出的“hello world ”,那么你知道它都经历了什么吗?今天我们就来聊聊这个话题。

一、从hello.c聊起
hello world.c

1
2
3
4
5
6
#include <stdio.h>

int main() {
printf("hello,world!\n");
return 0;
}

在linux下,使用 gcc 编译hello.c源文件,会在当前目录下默认生成 a.out 可执行文件,在终端输出hello,world!。

1
2
3
$ gcc hello.c
$ ./a.out
$ hello,world!

预编译器、汇编器as、链接器ld,实际上gcc 命令只是对这些不同程序的封装,根据不同的参数去调用不同的程序。

从 hello.c 到可执行文件的全过程,可分为4个步骤:

1、预处理
gcc -E hello.c -o hello.i 得到预处理文件,其中,-E 表示只进行预编译。
源文件在预编译阶段会被编译器生成.i文件,主要处理源代码文件中以“#”开头的预编译指令。如:宏定义展开,将被包含的文件插入到该编译指令的位置等。

2、编译
gcc -S hello.i -o hello.s 得到汇编文件,其中,-S 表示生成汇编文件。
编译就是把预处理完的文件,进行语法分析、词法分析、语义分析及优化后生成相应的汇编代码文件,这个过程是整个程序构建的核心过程,也是最复杂的部分。

3、汇编
as hello.s -o hello.o 或者 gcc -c hello.s -o hello.o,其中,-c 表示只编译不链接。
将汇编代码文件转变成机器可以执行的指令文件,即目标文件。也可以直接使用:gcc -c hello.c -o hello.o 经过预处理、编译、汇编直接输出目标文件。
为什么汇编器不直接生成可执行程序,而是一个目标文件呢?为什么要链接?这个我们后面会详细讨论。

4、链接
随着代码量的增多,所有代码若是都放在同一个文件里,那将是一场灾难。现代大型软件,动辄由成千上万的模块组成,每个模块相互依赖又相互独立。将这些模块组装起来的过程就是链接。
这些模块如何形成一个单一的程序呢?无非就是两种方式:1、模块间的函数调用;2、模块间的变量访问。函数访问必须知道函数地址,变量访问必须知道变量地址,所以终归到底就是一种方式,不同模块间符号的引用。


描述文字
© 2024 mengchao666 开心地使用 Stellar 主题,星际地球第
收集了 62 颗星星 ✧ 共 83.3k 粒星尘,好像写完一本 鲁迅 的《呐喊》了啊