目录
常识
我们平时写的代码和标准库是两回事,像C标准库提供给我们一些函数方便使用,降低程序员工作成本。比如写个printf("hello world"); 我们只是调用了库里的函数,并没有实现该函数,在链接的过程中,我们的代码和库中的结合起来(调用+实现)才生成可执行程序。
而一般所说的库有两个,动态库和静态库,链接也对应的有动态链接和静态链接。
动态链接
简单来讲就是不对那些组成程序的目标文件进行链接,等到程序要运行时才进行链接。也就是说,把链接这个过程推迟到了运行时再进行,这就是动态链接(Dynamic Linking)的基本思想。
空谈理论难以理解,下面我举个例子:
00年网络尚未普及时,张三在学校里想在周末打打游戏,但是宿舍没电脑,于是他问学长附件有没有网吧,学长告诉他一公里外有个网吧。这里相当于编写代码写了句printf("hello world");然后像编译器、链接器询问库的所在,和库建立联系。然后张三跑到网吧上网,这就相当于库函数跳转。
这种情况就是动态链接。张三需要跑到网吧去上网。
接下来有三个问题:
1、网吧现在装修扩建,会不会影响张三上网?————必然会。同理动态库升级也会影响程序员使用。
2、网吧被拆除会不会影响张三上网?————必然会。一样的动态库删库就无法使用了。
3、跑去一公里外的网吧上网耗费张三时间吗?————耗费。动态库也耗费一定的时间。
静态链接
静态链接是由链接器在链接时将库的内容加入到可执行程序中的做法。链接器是一个独立程序,将一个或多个库或目标文件(先前由编译器或汇编器生成)链接到一块生成可执行程序。
还是刚刚那个场景。张三觉得每天跑去网吧不方便,就在自己宿舍装了台电脑,这样就能直接上网不需要再每天跑来跑去了。
还是那三个问题:
1、网吧现在装修扩建,会不会影响张三上网?————不会。同理库升级不影响程序员使用。
2、网吧被拆除会不会影响张三上网?————不会。使用静态库的时候,链接过程不是我们写的代码与库产生关联,而是将我们的代码需要的库函数实现拷贝一份拿过来,这样就完成了静态链接,所以库不能用了不影响静态库。
3、现在张三不用跑去网吧,直接在宿舍上网即可。
两者的比较
这么看来静态链接貌似比动态链接方便咯?————实际上Linux下默认的是动态链接的。
它们各有优势,但是动态链接的优势重要性要大得多,或者说静态链接的缺陷是致命的。
从上面的例子来看,动态链接的缺点是库的状态会影响动态链接;优点是动态链接形成的可执行程序小,节约了资源(内存、磁盘、网络)。
静态链接相反,缺点是形成的可执行程序太大;优点是不受库的升级删除影响。
有人会说,现在电脑磁盘存储大小动辄几百G甚至1T,可执行程序大点也无所谓把?
————其实不然!如果我们现在安装的所有软件突然变大了100倍,比如下的10G游戏,变成了1000G,那还怎么运行,尤其是还要加载到内存,届时内存加载2、3个文件就扛不住了。
拿Linux下的动静态链接对比一下文件大小就知道了:
我们写一段小代码
gcc编译一下,可执行程序a.out 大小是8360byte:
现在是动态链接(linux下默认动态链接),dynamically意思就是动态地。
现在我们用静态链接方式编译刚才的代码,生成可执行程序mytest
静态链接,可执行程序大了100倍!这就是为什么默认使用动态链接的原因。
动态库与静态库
使用ldd命令可以查看动态可执行文件的信息。
libc.so.6就是动态库,并且是C标准库。将前缀lib,后缀so.6去掉,剩下的就是库名。
ldd 静态库,说:这不是一个动态可执行程序,那么以后该程序就和库无关了。
再看下指令,也都是动态链接。所以动态库是我们编写代码所需的重要东西,绝不能删除动态库,否则很多命令都执行不了。
用动态库的程序很多,但是库只有一个,所有C语言写的程序,都不会出现重复的库代码。
所以动态库是共享库。以后要下载一个C语言写的程序,不用下载库。
静态链接形式是libXXX.a,也是一样,去掉前缀lib,去掉后缀.a剩下的就是库名。
上面说了静态链接需要拷贝库,那么是拷贝.so中的内容吗? ————不是。
并且系统里必须存在.a结尾的静态库。如果没有,需要自己安装。
C标准库:yum install -y glibc -static
C++标准库:yum install -y libstdc++ -static
总结一下,动态链接找动态库,静态链接找静态库,不能互相找!