一直在用库,也一直不知道到啥是库。今天有时间,就了解一下库吧!(以动态链接库为题,但内容中也相关与静态库)。
希望能通过这篇博客,说明白这么几个问题:
1. 什么是静态链接库?什么是动态链接库?
2. 静态链接库和动态链接库的区别(两者各自的优点,缺点)?
3. 动态链接库的调用方式(隐式调用,显式调用两者区别及优缺点)。
4. 关于链接库一些相关的文件说明(比如.lib,.dll等)。
一、什么是静态链接库,什么是动态链接库?+ 二、两者区别
要想明白两者,先要懂什么是库。在写程序中,我们经常调库。所谓的库我理解就是共享程序,别人写好的指定功能的程序可以被自己拿来用去完成自己的功能(好吧,有点绕)。那我们是怎么能够用别人写的库的呢?这就自然而然的引出了链接库的概念。
静态链接库(static link library)指的是以静态的方式调用库中的某一个函数。那什么是静态的方式呢?静态就是指在主程序编译的时候,遇到了需要静态库中函数的地方,就把静态库中的函数导入文件中。直到文件结束,把所有的部分(包括静态库的函数)都放到可执行程序中。(一股脑全都放进去,听起来笨笨的)
动态链接库(dynamic link library)就是动态的方式啦!动态就是在程序编译的时候,即使发现了你需要动态库里面的函数。但是鉴于你现在并没有运行(不是真正的需要)。所以暂时先不放到你的可执行程序中。当可执行程序执行时并且到了调用动态库函数的时候,再去找到对应的函数,给输入得输出。
那二者之间的区别如何呢?孰优孰劣,且听我慢慢道来!
静态链接库的优点:
1. 可执行程序运行时速度较快
前面提到,所有要用的函数都已经在自己的程序里面了。直接拿来用比用的时候去找自然快了很多。
2. 不需要担心版本问题
这个其实我不是特别懂,但我简单理解为:当前的执行程序中已经包含上一代完整的链接库,如果在上一代可以成功运行,那么就相当于在新一代的情况下做用上一代的工具做上一代的事情。也没有什么大问题,可能性能差点。
静态链接库的缺点:
1. 太占内存了
对于每次调用静态链接库,都会把整个库放到可执行文件中。如果一个程序调用了很多个静态库,并且有很多个程序。那么对内存的耗费是极大的!而且不同程序中调用的可能是库的相同部分(术语叫公共代码),那这部分就会多次占用内存。
其实动态链接库,静态链接库作为对立的存在。优缺点基本上是互补的。
动态链接库的优点:
1. 对于内存空间大大节省
由于动态性的特点,可执行文件中不包括库中函数的代码,就省了这部分的空间。
2. 可扩展性更好
如果发生版本更新的情况,肯定是要优先使用新版本(要不为啥有新版本,肯定性能更好)。对于调用静态链接库来说就需要重新进行编译,这样才能把新版本带入可执行程序中。但动态链接库由于主函数和库的相对独立性,在库中做修改不会影响到可执行程序。在程序运行时,再动态链接新版的库。不需要再次经历编译的过程。
动态链接库的缺点:
1. 需要保护lib文件
动态链接肯定有动态链接的方式,这个方式就是lib文件(下文会具体介绍)。如果lib文件丢失,可执行程序就无法在调用时找到对应的函数,进而造成程序运行失败。
2. 运行时间较慢
这个和上面静态链接库基本相对。在此不再赘述。
三、动态链接库的调用方式:
动态链接库的调用方式分为两种:隐式调用和显式调用。其实两种方式最终的结果是相同的,但是编程的方式不太一样。
再此之前先解释一个概念。上文提到了.lib文件,下面介绍一下在动态库中lib文件的作用:
lib文件中存储的其实是在动态库中各个函数的坐标。在可执行程序调用动态链接库的时候就可通过lib文件找到想要的函数位置,再去.dll文件中找到具体的函数。
隐式调用:
隐式调用就是使用lib文件的方式进行调用,对于隐式调用来说lib文件就是必须的!
显式调用:
显式调用其实就是不使用lib文件完成动态链接。这就要求在写可执行程序的时候就指明要去哪里动态链接。说一下显式调用的步骤(其实我也不懂,从百度下copy的)
显式调用动态库步骤:
1、创建一个函数指针,其指针数据类型要与调用的 DLL 引出函数相吻合。
2、通过 Win32 API 函数LoadLibrary()显式的调用DLL,此函数返回DLL 的实例句柄。
3、通过 Win32 API 函数GetProcAddress()获取要调用的DLL 的函数地址,把结果赋给自定义函数的指针类型。
4、使用函数指针来调用 DLL 函数。
5、最后调用完成后,通过 Win32 API 函数FreeLibrary()释放DLL 函数。
参考网址为:https://zhidao.baidu.com/question/941369803910889532.htmllink
隐式调用和显式调用的区别?
从对步骤的论述上看,清晰看出显式调用更为麻烦,对编程人员的要求更高。但努力是有回报的,显式调用更加灵活,可模拟多态(就是封装性比较好,调用灵活)的特性。
注意:显示调用是可不使用lib文件,不是不可使用。
四、关于链接库的相关文件说明
Windows
静态链接库文件:.lib
动态链接库文件:.dll
Linux:
静态链接库文件:.a
动态链接库文件:.so——在Linux下动态链接库的命名规则为:lib+库名.so。例如:libcublas.so
在windows下,静态链接库和动态链接库的隐式调用文件都是以.lib结尾,但里面的内容大不相同哦。
介绍两个Linux下关于动态链接库的命令:
ldd + 程序名
举例:ldd main.c
作用:查看指定程序的动态链接库
nm -D + 动态链接库名字
举例:nm -D libcublas.so
作用:输出该动态链接库内所有的函数名
Linux下使用命令行调用库的时候分为三种:-I(大写的i)、-L(大写的l)、-l(小写的l)。对这三种不同的作用说明一下:
-I(大写的i)用于链接头文件(可曾想起include?)
-L(大写的l)用于链接到库搜索目录
-l(小写的l)用于链接到指定的动态库
同时在Linux下使用时,动态链接库的搜索顺序有一个优先级的划分,再此也说明一下(序号代表优先级顺序,即1最高):
1. 编译程序时加入-L/-l命令并指明路径
例:g++ -o test -L. -llib -Wl,rpath=./ test.cpp
2. 设置环境变量LD_LIBRARY_PATH
例:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
3. 设置 /etc/id.so.conf
对于这个说明一下,因为这个是read only文件。在修改之前要设置一下,并且修改之后需要sudo执行一下。
4. 把库放到系统默认路径中,即/usr/lib中
以上对于优先级的内容参考博客:https://www.cnblogs.com/vanishfan/archive/2013/01/15/2861211.htmllink
最后分享两个学习过程中看到的相关博客:
动态链接库实例博客:https://blog.csdn.net/qq_33113661/article/details/88991909link
解释.h .lib .dll关系的博客:https://www.cnblogs.com/azbane/p/7364060.htmllink
由于作者水平有限,如有错误之处,请在下方评论区指正,谢谢!