C/C++培训
达内IT学院
400-996-5531
我们在编写代码的时候经常用到已有的接口,他们是以库的形式提供给我们使用的,而常见形式有两种,一种常以.a为后缀,为静态库;另一种以.so为后缀,为动态库。那么这两种库有什么区别呢?
什么是静态库
前面所提到可重定位目标文件以一种特定的方式打包成一个单独的文件,并且在链接生成可执行文件时,从这个单独的文件中“拷贝”它自己需要的内容到最终的可执行文件中。这个单独的文件,称为静态库。linux中通常以.a(archive)为后缀
还是拿前面的例子来说,我们使用静态链接构建我们的可执行文件:
$ gcc -c main.c$ gcc -static -o main main.o -lm
在这个过程中,就会用到系统中的静态库libm.a。这个过程做了什么呢?首先第一条命令会将main.c编译成可重定位目标文件main.o,第二条命令的static参数,告诉链接器应该使用静态链接,-lm参数表明链接libm.a这个库(类似的,如果要链接libxxx.a,使用-lxxx即可)。由于main.c中使用了libm.a中的exp函数,因此链接时,会将libm.a中需要的代码“拷贝”到最终的可执行文件main中。
特别注意,必须把-lm放在后面。放在最后时它是这样的一个解析过程:
链接器从左往右扫描可重定位目标文件和静态库
扫描main.o时,发现一个未解析的符号exp,记住这个未解析的符号
扫描libm.a,找到了前面未解析的符号,因此提取相关代码
最终没有任何未解析的符号,编译链接完成
那如果将-lm放在前面,又是怎样的情况呢?
链接器从左往右扫描可重定位目标文件和静态库
扫描libm.a,由于前面没有任何未解析的符号,因此不会提取任何代码
扫描main.o,发现未解析的符号exp
扫描结束,还有一个未解析的符号,因此编译链接报错
如果把-lm放在前面,编译结果如下:
$ gcc -static -lm -o main main.o main.o:
In function `main':
main.c:(.text+0x2f):
undefined reference to `exp'collect2: error:
ld returned 1 exit status
更详细的解释也可以参考《一个奇怪的链接问题》。
我们看看最终生成的文件大小:
$ ls -lh main-rwxrwxr-x 1 hyb hyb 988K 6月 27 20:22 main
生成的可执行文件大小为988k。ls的高级用法可参考《ls命令常见实用用法》。
由于最终生成的可执行文件中已经包含了exp相关的二进制代码,因此这个可执行文件在一个没有libm.a的linux系统中也能正常运行。
什么是动态库
动态库和静态库类似,但是它并不在链接时将需要的二进制代码都“拷贝”到可执行文件中,而是仅仅“拷贝”一些重定位和符号表信息,这些信息可以在程序运行时完成真正的链接过程。linux中通常以.so(shared object)作为后缀。
通常我们编译的程序默认就是实用动态链接:
$ gcc -o main main.c -lm #默认使用的是动态链接
我们来看最终生成的文件大小:
$ ls -lh main-rwxrwxr-x 1 hyb hyb 8.5K 6月 27 20:25 main
可以看到,通过动态链接的程序只有8.5k!
另外我们还可以通过ldd命令来观察可执行文件链接了哪些动态库:
$ ldd main linux-vdso.so.1 => (0x00007ffc7b5a2000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fe9642bf000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe963ef5000) /lib64/ld-linux-x86-64.so.2 (0x00007fe9645c8000)
正因为我们并没有把libm.so中的二进制代码“拷贝”可执行文件中,我们的程序在其他没有上面的动态库时,将无法正常运行。
有什么区别
到这里我们大致了解了静态库和动态库的区别了,静态库被使用目标代码最终和可执行文件在一起(它只会有自己用到的),而动态库与它相反,它的目标代码在运行时或者加载时链接。正是由于这个区别,会导致下面所介绍的这些区别。
可执行文件大小不一样
从前面也可以观察到,静态链接的可执行文件要比动态链接的可执行文件要大得多,因为它将需要用到的代码从二进制文件中“拷贝”了一份,而动态库仅仅是复制了一些重定位和符号表信息。
占用磁盘大小不一样
如果有多个可执行文件,那么静态库中的同一个函数的代码就会被复制多份,而动态库只有一份,因此使用静态库占用的磁盘空间相对比动态库要大。
扩展性与兼容性不一样
如果静态库中某个函数的实现变了,那么可执行文件必须重新编译,而对于动态链接生成的可执行文件,只需要更新动态库本身即可,不需要重新编译可执行文件。正因如此,使用动态库的程序方便升级和部署。
依赖不一样
静态链接的可执行文件不需要依赖其他的内容即可运行,而动态链接的可执行文件必须依赖动态库的存在。所以如果你在安装一些软件的时候,提示某个动态库不存在的时候也就不奇怪了。
即便如此,系统中一班存在一些大量公用的库,所以使用动态库并不会有什么问题。
复杂性不一样
相对来讲,动态库的处理要比静态库要复杂,例如,如何在运行时确定地址?多个进程如何共享一个动态库?当然,作为调用者我们不需要关注。另外动态库版本的管理也是一项技术活。这也不在本文的讨论范围。
加载速度不一样
由于静态库在链接时就和可执行文件在一块了,而动态库在加载或者运行时才链接,因此,对于同样的程序,静态链接的要比动态链接加载更快。所以选择静态库还是动态库是空间和时间的考量。但是通常来说,牺牲这点性能来换取程序在空间上的节省和部署的灵活性时值得的。再加上局部性原理,牺牲的性能并不多。
总结
静态库和动态库具体是何如链接的已经超出了本文的介绍范围,本文仅简单介绍了一些静态库和动态库的区别,另外文中提到的在其他的linux系统,也指的是同样处理器架构的系统。
当你还在担心能否就业时,达内学员提前被企业录取;当你转辗于各大招聘会时,达内学员收到了高薪offer;当你在各大招聘网站投递简历时,达内学员中有人一毕业进入五百强名企。所以选择很重要。找C++培训班,选达内就对了。
填写下面表单即可预约申请免费试听!怕钱不够?可就业挣钱后再付学费! 怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!
Copyright © 京ICP备08000853号-56 京公网安备 11010802029508号 达内时代科技集团有限公司 版权所有
Tedu.cn All Rights Reserved