我们在学习编译器时,我们不仅要只会使用编译器,还要理解程序的编译过程。一个程序存在两个不同的环境。第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令;第2种是执行环境,它用于实际执行代码。本篇文章将在讲解程序的翻译过程中来介绍gcc/g++的使用。
目录
程序的翻译过程:
- 预处理(进行宏替换)
- 编译(生成汇编)
- 汇编(生成机器可识别代码)
- 链接(生成可执行文件或库文件)
为什么程序翻译要有怎么多过程,这里通过了解语言的发展以及自举或许可以理解。那么什么是自举呢,就是通过自己的语言实现自己的编译器。那么这时候就有问题:是先有语言还是编译器?我们这里慢慢解释。
最开始,计算机只能识别二进制,我们要向计算机传递信息时,只能通过穿孔纸带让CPU识别,也就是最初的第一代语言:机器语言。

但是于这种语言人类很难理解,为了更好的与计算机进行沟通,发展出了第二代语言:汇编语言,用助记符代替了操作码,用地址符号或标号代替地址码,这样就用符号代替了机器语言的二进制码。使用符号代替二进制码进行相关操作。

这里就可以使用汇编代码写软件了,但是既然可以使用汇编语言写软件,也就可以使用汇编语言写汇编语言的编译器,这里就实现了汇编语言的自举。很明显这里可得:是先规划的语言,再通过语言写的编译器。
后来人们认为汇编语言还是复杂,于是就发展有了第三代语言:高级语言C语言,是一种接近于人们使用习惯的程序设计语言。同汇编语言相同,所以高级语言也可以实现自举,但是这里就有一个问题了:高级语言是先将代码转换为汇编代码,再转换为二进制让机器识别,还是直接转换为二进制让机器识别?
首先我们要知道语言发展的每一步都是经历过很多困难的,二进制重写高级语言与汇编语言重写高级语言相比无疑是比较困难的,所以说用汇编代码写高级语言是更加合适的。
这里就可以理解为什么程序翻译过程中要有编译(生成汇编)和汇编(生成机器可识别代码)的过程了。理解这里之后我们继续讲解。
格式 gcc [选项] 要编译的文件 [选项] [目标文件]

通过vim编译code1.c文件,然后用 gcc 编译code1.c,如果这里没有加选项 -E,会将程序的翻译过程全部进行完,-E 就是让 gcc 预处理完就停下来,如果不加 -o 会将文件预处理完的内容直接打印到屏幕上。
这里可以用vs指令查看多个文件:

可以发现这里预处理后的 .i 文件比 .c 源文件多出了八百多行,多出的主要是包含头文件,也就是把 stdio.h 的内容拷贝了过来。还通过条件编译,实现了对代码的动态裁剪。宏常量M也被替换,注释也被去除。
这里条件编译就可以理解很多软件有免费版本和收费版本,但只需要维护一份代码。

这里也可以直接通过gcc -S .c 文件,-S让文件翻译到编译结束后就停下来。

可以发现 .s 文件内部已经生成了汇编代码。
-c 就是将文件翻译进行到汇编结束后就停下来,这里生成 .o 目标文件

通过vim打开文件,可以发现已经生成了我们看不懂的可重定位二进制文件。

可以使用od命令查看二进制文件,但也是看不懂的

gcc 指令记忆 -ESc ,与键盘上的退出键相同,但要注意大小写。
生成文件的后缀 -iso
在当先文件目录下是,直接 ./文件名 即可执行。因为执行一个程序需要找到它的位置,这里是相对路径,. 代表当前目录。

可执行文件是由我们的代码+头文件+库组成的,这里就涉及到库的知识,我们下面讲解:
动态链接优缺点:
静态链接优缺点︰
ldd指令查看可执行程序所依赖的库。gcc 后加-static 可以链接静态库

下面可以发现静态链接比动态链接生成的可执行程序体积要大很多。

默认情况下,云服务器是没有安装c静态库的,只有动态库,安装方法:
g++ 可以编译C语言和C++,但是gcc只能编译C语言,其他操作是类似的。
本篇结束!
