Linux编译器——gcc/g++的使用
文章目录
一、背景知识
gcc是c语言的编译器,g++是c++的编译器,它们的核心作用是把程序从对应的文本类文件翻译为二进制可执行文件。二者使用语法一样,这里以gcc作为演示
1.程序的翻译
一个程序从文本类文件到二进制可执行文件有以下四步
- 预处理
执行头文件展开,条件编译,宏替换,去注释等操作,预处理里后仍是c语言- 编译
将c语言翻译为汇编语言- 汇编
由汇编语言翻译成可重定位目标二进制文件,但此时还不可以执行
此时的汇编只把我们自己的代码进行翻译形成二进制文件- 链接
将我们自己形成的.obj文件和库文件合并,形成可执行程序
二、gcc的使用
如前文所诉,程序的翻译可以分为四步,那么gcc如何完成以上四步呢?下面一一介绍。
1.通过gcc直接生成可执行文件
gcc指令可以一次性的完成以上四步,就比如我创建了一个名为myfile.c的文件,我可以通过指令gcc myfile.c
在当前目录下生成可执行文件。一般生成的可执行文件名称默认是a.out。如果我们不想要这个名字,我们可以使用-o
选项加上想生成文件的名字,比如我想让生成的文件名为myfile
,就可以将原来的指令修改为gcc myfile.c -o myfie
或是gcc -o myfile myfile.c
。需要记住的是,-o
选项后面跟着的那个文件名就是我们想生成的文件名。下面看演示。
可执行文件生成后,我们可以通过./文件名的方法
执行该文件。
这是我在myfile.c文件中写的代码。
下面是执行结果
当然gcc指令也可以通过背景知识中的四个步骤,一步一步生成新文件。
2.通过gcc执行程序的翻译过程
正如前文所诉,程序的翻译有四个过程,预处理,编译,汇编和链接。下面将一一演示。(这里主要是为了说明程序的编译过程,了解即可,实际中都是用上面直接翻译的方法)
2.1 预处理(进行宏替换)
我们可以使用选项-E
,该选项的作用是让 gcc 在预处理结束后停止翻译过程。同时,后缀名为.i的文件表示已经过预处理的C原始程序。
这里可以看到,经过预处理,文件的内存变大了不少。使用vim myfile.i
查看该文件。
然后在底行模式下输入vs myfile.c
进行比对。
可以发现,原来的注释没有了,头文件展开后代码到了八百多行,宏定义中的M也替换成了100。
2.2 编译(生成汇编)
在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。
这里我们采用-S
选项,该选项是使程序完成编译后停下来。从而生成汇编程序(使用后缀.s表示)。
这里可以使用指令gcc -S myfile.c -o myfile.s
表示从.c文件开始翻译,完成汇编过程后停止,生成文件myfile.s,不过我们之前已经生成了文件myfile.i,所以可以使用指令gcc -S myfile.i -o myfile.s
。这样还省去了再预处理一次的步骤。后面的汇编与链接也是一样,可以基于上一步生成的文件处理。
可以使用指令vim myfile.s
打开查看。
此时文件内容已经变为了汇编语言。
2.3 汇编(生成机器可识别代码)
汇编阶段是把编译阶段生成的“.s”文件转成目标文件。这里我们采用-c
选项,该选项是使程序完成编译后停下来。从而生成汇编程序(使用后缀.o表示)。注意此时的文件还不可执行。
这里可以使用指令gcc -c myfile.s -o myfile.o
表示从.s文件开始翻译,完成汇编过程后停止,生成文件myfile.o。
使用指令vim myfile.o
打开查看。
此时已经成为二进制文件。
2.4 链接(生成可执行文件或库文件)
使用命令gcc myfile.o -o myfile
生成可执行文件myfile,此时文件就可以执行了。
执行方法还是./myfile
三、函数库的介绍
这里做一个概念的介绍,了解即可。
- 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?
- 最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。
函数库一般分为静态库和动态库两种
- 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”。
- 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,比如 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件。
- gcc默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证。