文章目录
- 前言
- 一、gcc 是什么?
- 二、使用步骤
- 1.预编译
- 2.编译
- 3.汇编
- 4.链接
- 三、动静态库
- 1.概念
- 2.区别
前言
在Linux环境下,除了学好编辑器 vim 的使用,还需要学会C语言的编译器 gcc 的功能,否则代码无法翻译成可执行程序。本文将介绍 gcc 的常规使用方法,以及一个C语言程序,在链接的时候发生了什么。
提示:以下是本篇文章正文内容
一、gcc 是什么?
GCC原名为GNU C语言编译器(GNU C Compiler),只能处理C语言。但其很快扩展,变得可处理C++,后来又扩展为能够支持更多编程语言,如Java、Go等等。其作用就是,将一个C语言文件,执行翻译的过程,从 .c 文件变成 .exe 文件,这样就可以执行( .c 文件只存放代码,相当于记事本)。可以看这篇文章,了解翻译的过程:你知道.c文件是如何变成.exe文件的吗。
翻译过程可以大致分为:预编译、编译、汇编、链接。在链接期间,涉及到链接器的一些小知识,本文也会讲解。
二、使用步骤
1.预编译
在 Linux 中输入指令如下,其作用主要包括:宏定义,文件包含,条件编译,去注释等。
gcc -E test.c -o test.i
- 选项“-E”,该选项的作用是让 gcc 在预编译结束后停止翻译过程。
- 选项“-o”是指目标文件(所以它后面跟的是想要生成的文件名), “.i” 文件为已经过预处理的C原始程序。
如下图:
2.编译
在 Linux 中输入指令如下,在这个阶段中:gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。
gcc -S test.i -o test.s
- 选项“-S”,该选项只进行编译而不进行汇编,生成汇编代码
如下图:
3.汇编
在 Linux 中输入指令如下,其作用是:把编译阶段生成的“.s”文件转成目标文件。
gcc -c test.s -o test.o
- 选项“-c”,该选项将汇编代码已转化为“.o”的二进制目标代码。
如下图:
4.链接
在 Linux 中输入指令如下,其作用是:合并符号表、合并段表等等。
gcc test.o -o test
如下图,可以很明显地看到,生成了一个可执行文件test。
当然了,上面只是为了理解翻译过程,但是其实可以一步到位生成可执行文件,那就是 gcc test.c -o test 可以将 test.c 文件生成 可执行文件 test。 当然,最简单的做法是 gcc test.c 但是这样无法控制生成的文件名,其默认目标文件名是 a.out 。
三、动静态库
1.概念
在上文内容其实涉及到一个重要概念:函数库。
库分为两种:静态库和动态库。其命名规则是:前缀+文件名+后缀。如下图,静态库后缀是.a ,动态库后缀是 .so,其前缀都是 lib 。
静态库:libXXXXX.a
动态库:libXXXXX.so
我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现“printf”函数的呢?
实际上是:Linux系统把这些函数实现都被做到名为 libc.so.6 (Linux默认使用动态库)的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。
2.区别
我们先看到动态库:他是专门让编译器,对用户的程序进行动态链接的。
动态链接:链接的时候,找到动态库,拷贝动态库中的我所需要的代码的地址到我自己的可执行程序中相关的位置。
动态链接成功:我们的程序,还是依赖动态库,一旦动态库缺失,我们的程序便无法运行!
我们根据上面使用 gcc 的示例文件test,如下,先执行 ldd test,查看其依赖库,是 libc.so.6 此时就可以看出是依赖动态库了;再执行 file test,查看其信息可得,确实Linux 默认使用动态库。
静态库是专门让编译器,对用户的程序进行静态链接的。
静态链接:链接的时候,找到静态库,拷贝静态库中的我所需要的代码到我自己的可执行程序中。
静态链接成功:我们的程序,不依赖任何库,自己就可以独立运行。
如下,我们使用静态链接的方法生成 test-static 文件,从两个箭头指向的地方,可以明显看出,test-static 比 test 大了百倍,其仅仅是一个打印 Hello World 的程序生成,区别如此之大。再用 ldd 指令查看,不是动态的,file 指令查看详细信息,静态链接。(注意,编译此程序需要用到libc库文件,而系统中无法找到libc的静态库文件,需要下载安装:sudo yum install -y glibc-static)
根据以上内容,可以得出结论:
静态库:因为自身拷贝的问题,比较浪费空间。
动态库:因为可以做到被大家共享方法,所以真正的实现永远都是在库中,程序内部只有地址,比较节省空间。
Linux默认使用的是动态链接和动态库!如果进行大型项目开发,其文件非常巨大,如果使用静态库,其所消耗空间资源比动态库要多上接近一百倍,所以使用动态库更好一些。