🏖️作者:@malloc不出对象
⛺专栏:Linux的学习之路
👦个人简介:一名双非本科院校大二在读的科班编程菜鸟,努力编程只为赶上各位大佬的步伐🙈🙈
目录
- 前言
- 一、gcc/g++的介绍
- 二、程序的翻译环境
- 2.1 链接
- 2.2 动静态库
- 2.2.1 动态库的感性理解
- 2.2.2 感性理解静态库
- 2.2.3 Linux默认使用的库
- 2.2.4 动静态库与动静态链接的理解
前言
本篇文章我们将要来学习的是Linux下的两种编译器,gcc是C语言的编译器,g++是C++的编译器,它们的使用方式基本一致所以接下来我们只需了解其中一种编译器的使用指令即可;同时本文还将重点谈谈链接过程,动静态库的概念。
一、gcc/g++的介绍
gcc(GNU C Compiler)是 GNU 退出的功能强大、性能优越的多平台编译器,其可以编译利用 C语言、C++ 和 Object C 等语言编写的程序。gcc 编译出的目标代码质量非常好,编译速度也很快,并且 gcc 是一个交叉平台编译器,它能够在当前处理器平台上为多种不同体系结构的硬件平台开发软件,因此尤其适合嵌入式领域的开发编译。
二、程序的翻译环境
我们通常把一个或多个源文件(.c)形成一个(.exe)可执行程序叫做翻译环境,它又分为预处理、编译、汇编和链接这四个步骤,关于这些步骤的详细细节大家可以看我之前写的这篇博客,下面我们再来详谈一下链接过程。
2.1 链接
所谓链接过程到底是在干什么? 链接过程其实就是在链接库–>动静态库。想想为什么我们能直接使用printf函数?printf函数是我们自己实现的吗?不是,它是库提供给我们的。那为什么库要提供给我们呢?很简单,为了提高开发效率,如果我们连输入输出函数都要我们用户来实现,你想想这个我们开发的门槛是不是比较高?所以为了提高开发效率,我们将一些函数封装在库中(库函数),在链接过程我们使用了对应的目标函数就从库中加载对应的函数代码和数据。
接下来我们就来初步认识一下动静态库。
2.2 动静态库
我们为什么能在Linux下进行C、C++代码的编写和编译呢? 这是因为Linux系统默认已经携带了语言级别的头文件和语言对应的库!!
如何查看我们的链接过程?
ldd 可执行文件
/lib64/libc.so.6是libc-2.17.so的一个软链接,/lib64/libc.so.6文件里放的是libc-2.17.so文件的路径信息,读取文件/lib64/libc.so.6时,系统会自动将访问者导向文件libc-2.17.so,你也就可以认为libc-2.17.so就是我们现在使用的C语言库!
库分为两种一种是静态库,在Linux下通常以.a为后缀,另一种是动态库,通常以.so为后缀;而Windows中静态库后缀为.lib,动态库后缀为.dll。虽然名称上有所不同,但是它们之间本质上的功能也是大致差不多的。
2.2.1 动态库的感性理解
下面我用文字来描述一下上图表示的情景:小库同学在只因中学读书,他还没来学校的时候就向学长们打听了学校附近的网吧,学长告诉他出了北门往前走100m就有一个只因网咖,那里的电脑配置也非常好,于是小库就记下了只因网咖的地址,心里想着以后有时间就去放松放松。小库也不是一个贪玩的人,他每天都有一个学习计划清单,这天他在吃完饭之后就打算去网咖放松放松,于是他在脑海里回想起了之前学长告知他的地址,它通过地址找到了网咖并且在里面舒服的找了一个包厢在网吧里面欢快的上着网,开心完之后他又回到宿舍完成接下来的学习任务。
我们来感性理解一下这个过程:学长告诉了你网咖的地址,这就相当于你知道了某个函数的地址,你记住了这个函数的地址相当于你将这个函数加入了符号表,你通过地址找到了这个网咖这就代表着链接成功。那么小库为什么要去网咖呢?因为小库自己的电脑配置不行,而网咖里面的电脑配置好网速快体验好,这就相当于去调用库函数,网咖就对应着动态库,它的里面有很多台电脑对应不同的库函数,在上完网回到宿舍这个过程对应着库函数调用完成回到主函数,回到主函数之后继续执行下面的操作。网咖里面可以让任何人都能上网,网咖它也就是一个共享库。假如有一天只因网咖倒闭了,那么很多人都不能去上网了,这也就对应着我们的动态库没了的话,那么我们的库函数都不能被使用了!!不能被使用就意味着整个学习任务无法完成,程序编译错误了。
2.2.2 感性理解静态库
我们来感性理解一下这个过程:之前你跟你的老爸谈过一个条件,你如果期末考试考了年级前10,你的老爸就答应帮你买一台电脑。小库其实也是个学霸,果不其然小库这次靠近了年级前10,他的老爸就打算给它买一台电脑,你也如愿以偿的有了自己的电脑,那么如果有一天只因网咖倒闭了那么你还能上网吗?当然能,因为此时你已经有了电脑,它倒闭了于你来说关系不大了。你的老爸给你买电脑的过程就对应着拷贝一份你所需的代码到你的程序当中,所以就算它倒闭了,你也能正常使用电脑。
2.2.3 Linux默认使用的库
Linux默认使用的是动态库还是静态库?
另外我们之前讲过,Linux下的大部分指令都是由C语言写的,下面我们来看看这些指令使用的是什么库。
我们可以看到这些指令都是使用的动态库,这也就证明了Linux下默认使用的就是动态库,动态链接!!
Linux下默认使用的是动态库。在Linux系统中,大部分系统库和第三方库都是以动态库的形式提供的,这些库的文件一般以“.so”为后缀,被称为共享库或动态链接库。当程序需要调用库函数时,动态链接器会在系统的默认库路径中搜索相关的动态库文件,将其加载到内存中,并在程序运行时解析链接。虽然Linux系统中也提供了静态库(以“.a”为后缀)的支持,但是在默认情况下,编译器和链接器都会使用动态库。如果需要使用静态库,需要显式指定使用静态链接方式进行编译和链接,一般使用命令行选项“-static”来实现。
如何使用静态库呢? 编译链接的时候带上-static选项。
我们可以看到静态链接的文件大小比动态链接的文件大上将近100倍,这还仅仅是在调用printf函数的基础上,如果我们还使用了其他的库函数那么这个文件将会非常之大!!!
在静态链接的情况下,编译器会将所需的库函数的机器码复制到可执行文件的文本段中,这样可执行文件就包含了所有需要的代码,可以在没有其他依赖项的情况下运行。因此,如果你的程序使用了printf函数,那么整个C标准库的代码都会被链接到最终的可执行文件中。这会使得可执行文件变得比较大,但也会确保程序在其他环境中运行时能够正确地执行。
注:Linux 指令也是用 C语言写的可执行程序,这些指令也是动态链接 C 标准库生成的。如果我们删掉了 C 动态库,那么很多 Linux 指令都会无法使用了。C语言的动态库只有一份,不会出现重复的库代码。因此,动态库也称为共享库。以后我们要是下载一个 C语言写的程序,不需要卸载 C语言的标准库。
2.2.4 动静态库与动静态链接的理解
动静态库的认识:
- 库分为动静态库(专门让编译器对用户程序进行静态链接的)和动态库(专门让编译器对用户程序进行动态链接的)
- 静态库和静态链接:链接的时候,如果是静态的,拷贝静态库中我所需要的代码到我自己的可执行程序中
- 动态库和动态链接:链接的时候,如果是动态的,拷贝动态库中我所需要的代码的地址到我自己的可执行程序中相关的位置
- 静态链接成功:我们的程序不依赖任何库,自己就可以独立运行
- 动态链接成功:我们的程序还是依赖动态库,一旦动态库缺失,我们的程序就无法运行
- 静态库:因为自身拷贝的问题比较浪费空间
- 动态库:因为可以做到被大家共享,所以真正的实现永远都是在库中,程序内部只有地址,比较节省空间。
- 静态库和动态库:Linux默认使用的是动态链接和动态库。
静态链接(static linking)和动态链接(dynamic linking)是编译器和操作系统中常见的两种库链接方式。
静态链接:
静态链接是指在编译时将所有需要用到的库函数的机器码拷贝到可执行文件中,使得可执行文件本身包含了所有的代码和数据,因此在运行时不需要依赖外部库。这种链接方式的优点是运行时速度快、依赖性低,但缺点是可执行文件比较大,并且如果库函数更新,需要重新编译链接可执行文件才能使用新版本的库函数。
动态链接:
动态链接是指在运行时才将需要用到的库函数的机器码加载到内存中,使得多个程序可以共享同一份库函数的代码和数据。这种链接方式的优点是可执行文件比较小,且多个程序可以共享同一份库函数,减少了内存占用,同时库函数更新时只需要更新库文件,不需要重新编译链接可执行文件。缺点是运行时速度较慢,并且可能存在依赖性问题,即如果某个库函数更新或者丢失,就会导致程序无法运行或者运行出错。
在实际应用中,一般会根据实际需求选择静态链接或者动态链接。如果需要程序独立运行或者需要最大的运行速度,就选择静态链接;如果需要节约内存或者需要多个程序共享同一份库函数,就选择动态链接。
本篇文章的内容就讲到这里了,如果有任何疑问或错处欢迎大家评论区相互交流orz~🙈🙈