从源程序到可执行性程序,文本文件→预处理→编译→汇编→链接→可执行文件【helloworld】(2)

这篇博客详细说明从源程序到可执行性程序,预处理--> 编译--> 汇编--> 链接,详细过程。

  • 从源程序到可执行性程序
  • 集成开发环境
  • 预处理
  • 编译
  • 汇编
  • 链接
  • 总结

从源程序到可执行性程序

集成开发环境

对于集成开发环境(IDE,Integrated Development Environment )而言,减少了环境配置,合并了流程,使其便于快速开发。 Qt 开发环境或者vs开发环境等只需一步即可。

从源程序到可执行性程序,文本文件→预处理→编译→汇编→链接→可执行文件【helloworld】(2)_第1张图片
或者在vs环境下我们直接运行即可。
从源程序到可执行性程序,文本文件→预处理→编译→汇编→链接→可执行文件【helloworld】(2)_第2张图片

源程序就是一个.txt 的普通文本文件,但是实际上经历了哪些过程,成为可执行性文件的呢?

分为下面四个步骤:

预处理 -> 编译 -> 汇编 -> 链接
从源程序到可执行性程序,文本文件→预处理→编译→汇编→链接→可执行文件【helloworld】(2)_第3张图片

我们前面提到在windows环境的集成开发环境里面这些步骤编译器直接执行了。所以我们在linux平台没有IDE的环境下进行演示。

unix /linux 环境下,通常没有界面,所以很少有集成开发环境。所有的开发均是在命令行模式下开发的。我们以 vim 为文本编辑器,以 gcc 为编译器演示从源程序到可执行性程序的过程。

我们先给出完成过程然后进行分步演示:

① vim hello.c
② gcc -E hello.c -o hello.i //处理文件包含,宏和注释
③ gcc -S hello.i -o hello.s //编译为汇编文件
④ gcc -c hello.s -o hello.o //经汇编后为二进制的机器指令
⑤ gcc hello.o -o hello //链接所用的到库

我们先使用文本编译器编写代码:
通过 命令 vi hello.c 编写文本文件的代码:

#include
int main()
{
     
        printf("hello world\n");
        return 0;
}

预处理

gcc -E hello.c -o hello.i E是编译型参数 -o 表述output 输出 为hello.i
经过gcc -E命令可生成预处理之后的源文件

执行结果为:
预处理

我们来查看一下hello.i文件里面的内容。
这个文件很长,我们只截取最后一部分:
从源程序到可执行性程序,文本文件→预处理→编译→汇编→链接→可执行文件【helloworld】(2)_第4张图片
“预处理”过程:

1.处理所有条件编译指令,如:#ifndef、#ifdef、或者#if等。

2.处理所有文件包含指令,如:#include ,预处理器会将stdio.h文件内容插入到该指令位置。

3.删除所有注释代码,如"//“和”//"。

4.添加文件标识和行号,以便后续代码编译或调试时错误或警告信息提供行号或文件标识。

我们发现源程序中所在的 int main()之后的内容都在,但是int main ( ) 上面include没有了。那么预处理之后int main ( ) 上面的所有内容都是由#include 所替换,#include是包含,这里int main ( ) 上面的所有内容其实就是对于头文件 stdio.h 的一次展开。

编译

gcc -S hello.i -o hello.s S是参数,s代表文件后缀
生成编译之后的hello.s汇编文件。

执行结果为:
编译
我们打开hello.s文件
从源程序到可执行性程序,文本文件→预处理→编译→汇编→链接→可执行文件【helloworld】(2)_第5张图片

我们可以看到 打开hello.s文件之后,最起码会感觉认识一些,如果学习过汇编的读者就知道上面就是汇编语言代码。

汇编

gcc -c hello.s -o hello.o

执行结果为:
汇编
我们来查看一下生成的hello.o文件:
从源程序到可执行性程序,文本文件→预处理→编译→汇编→链接→可执行文件【helloworld】(2)_第6张图片
我们可以看到生成的 hello .o 文件已经是二进制文件。但是能不能执行呢?
我们先来测试一下:运行hello.o文件

我们可以看到 hello .o 文件 没有执行权限,因为它不是一个可执行性的二进制文件,那么我们现在给hello.o 加一个可执行权限。

(关于文件的权限读者在linux博客查看,这里不做过多说明。)
从源程序到可执行性程序,文本文件→预处理→编译→汇编→链接→可执行文件【helloworld】(2)_第7张图片
我们可以看到给hello.o加上可执行性权限,文件名变为绿色表示文件具备可执行性权限。

执行结果为:
提示:不可执行的二进制文件
上面会出现错误,不能执行。

给出提示:不可执行的二进制文件。

我们可以看到hello.o是一个不可执行的二进制文件。

链接

gcc hello.o -o hello 生成 hello 具有可执行性的二进制文件。
链接

当然我们也可以直接使用

gcc hello.o

会默认生成a.out可执行性文件。

接下来我们执行 a.out 可执行性文件:
执行 a.out 可执行性文件
我们来查看一下hello可执行文件的内容:
从源程序到可执行性程序,文本文件→预处理→编译→汇编→链接→可执行文件【helloworld】(2)_第8张图片

我们可以明显看到比hello.o 里面的内容多。

所以链接会链接标准库所需要的函数,例如我们这里用到的printf函数并不是我们自己实现的,是通过链接库来实现的,所以链接之后最终的可执行性文件内容会增加。

总结

① 预处理: 预处理根据预处理命令组装成新的 c 程序,不过常以 i 为扩展名。

② 编 译: 将得到的 .i 文件翻译成汇编代码的 .s 文件。

③ 汇 编: 将汇编文件翻译成机器指令,并打包成可重定位目标程序的 .o 文件。
该文件是二进制文件,字节编码是机器指令。

④ 链 接: 将引用的其他 .o 文件并入到我们自己编写的程序所在的 .o 文件中,处理之后得到最终的可执行文件。

从源程序到可执行性程序,文本文件→预处理→编译→汇编→链接→可执行文件【helloworld】(2)_第9张图片
从源程序到可执行性程序,文本文件→预处理→编译→汇编→链接→可执行文件【helloworld】(2)_第10张图片

有时候我们需要逃离继承开发环境,所以在linux系统里面编码,继承开发环境在一定程度上是便捷的,但是往往很多内容本质的剖析并不完善。上面我们就在linux平台把从源程序到可执行性程序的每一步都进行剖析。这也是我们之后要学习linux开发环境的原因之一。

Linux 环境虽然简陋,但是向我们呈现出的是本质的内容,一上手,就用集成开发环境可能有些细节,很久都搞不明白。

你可能感兴趣的:(C)