區別:1、動態庫的後綴為“.so”,靜態庫的後綴為“.a”。 2.如果靜態函數庫改變了,那麼程式必須重新編譯;而動態函數庫的改變並不影響程式。 3.相對於靜態函式庫,動態函式庫在編譯的時候並沒有被編譯進目標程式碼中,使用者的程式執行到相關函數時才呼叫該函數函式庫裡的對應函數,因此動態函式庫所產生的可執行文件比較小。
本教學操作環境:linux7.3系統、Dell G3電腦。
一、函式庫的基礎概念:
#在windows平台和linux平台下都大量存在著函式庫。本質上來說函式庫是一種可執行程式碼的二進位形式,可以被作業系統載入記憶體執行。由於windows和linux的本質不同,因此二者函式庫的二進位是不相容的。通俗的說就是把這些常用函數的目標檔案打包在一起,提供對應函數的接口,以便於程式設計師使用。使用函數時,只需要包對應的頭檔即可。依照函式庫的使用方式又可分為動態函式庫和靜態函式庫,在不同平台下對應後綴也有所不同。
WINDOWS下:.dll 後綴為動態函式庫,.lib 後綴為靜態函式庫;
LINUX下:.so
後綴為動態函式庫,.a
後綴為靜態庫。
二、靜態函式庫與靜態連結
#靜態函式庫:
靜態庫可以簡單的看成一組目標檔案的集合,也就是許多目標檔案經過壓縮打包後形成的檔案。例如在我們日常程式設計中,如果需要使用printf函數,就需要包stdio.h的庫文件,使用strlen時,又需要包string.h的庫文件,可是如果直接把對應函數源碼編譯後形成的.o檔案直接提供給我們,將會對我們的管理和使用上造成極大不便,於是可以使用「ar」壓縮程式將這些目標檔案壓縮在一起,形成libx.a靜態函式庫檔案。
附註:靜態函式庫命名格式:lib "函式庫名稱” .a(後綴) 例:libadd.a就是一個叫add的靜態函式庫
靜態鏈接:
對於靜態函式庫,程式在編譯連結時,將函式庫的程式碼連結到可執行檔中,程式執行時不再需要靜態函式庫。在使用過程中只需要將函式庫和我們的程式編譯後的檔案連結在一起就可形成一個可執行檔。
透過一個例子來了解下如何將我們自己寫的頭文件和程式碼同時進行編譯鏈接,最終生成可執行檔:
/main.c/ #include <stdio.h> #include "add.h" int main() { int ret = add(3, 4); printf("3 + 4 = %d\n",ret); return 0; } /add.c/ #include "add.h" int add( int x, int y) { return x + y; } /add.h/ #pragma once #include <stdio.h> int add( int x, int y); /Makefile/ main : main.c libadd.a gcc main.c -L . -ladd -o main //-L为指定路径 .为当前目录下 -l+库名字,编译器可在指定目录下自己寻找名为add的库文件 libadd.a : gcc -c add.c -o add.o //ar -rc将多个编译后的文件打包为一个静态库文件 ar -rc libadd.a add.o .PHONY:clean clean: rm main libadd.a
make後輸出截圖:
<3>缺點:
1、記憶體和磁碟空間浪費:靜態連結方式對於電腦記憶體和磁碟的空間浪費十分嚴重。
假如一個c語言的靜態庫大小為1MB,系統中有100個需要使用到該庫文件,採用靜態鏈接的話,就要浪費進100M的內存,若數量再大,那浪費的也就更多。例如下圖:程式1和程式2都需要用到Lib.o,採用靜態連結的話,那麼物理記憶體中就會存放兩份對應此檔案的拷貝。
2、更新麻煩:
例如一個程式20個模組,每個模組只有1MB,那麼每次更新任何一個模組,使用者都得重新下載20M的程式。
三、動態函式庫與動態連結
#<1>動態函式庫:
程式在運行時才去連結動態庫的程式碼,多個程式共享庫的程式碼。一個與動態函式庫連結的可執行檔僅包含它所用到的函數入口位址的一個表,而不是外部函數所在目標檔的整個機器碼。
附註:動態函式庫命名格式:lib "函式庫名稱” .so(後綴) 範例:libadd.so就是一個叫add的動態函式庫
<2>動態鏈接:
由於靜態連結具有浪費記憶體和模組更新困難等問題,提出了動態連結。基本實現思想是把程式按照模組拆分成各個相對獨立部分,在程式運行時才將他們連結在一起形成一個完整的程序,而不是像靜態連結那樣把所有的程式模組都連結成一個單獨的可執行檔。所以動態連結是將連結過程延後到了執行時才進行。
同样,假如有程序1,程序2,和Lib.o三个文件,程序1和程序2在执行时都需要用到Lib.o文件,当运行程序1时,系统首先加载程序1,当发现需要Lib.o文件时,也同样加载到内存,再去加载程序2当发现也同样需要用到Lib.o文件时,则不需要重新加载Lib.o,只需要将程序2和Lib.o文件链接起来即可,内存中始终只存在一份Lib.o文件。
动态库和动态链接的例子依然使用上面的代码,输出结果也相同,唯一需要改变的就是Makefile文件。
/Makefile/ main : main.c libadd.so gcc main.c -L . -ladd -o main libadd.so : gcc -fPIC -shared add.c -o libadd.so //-shared表示输出结果是共享库类型的 -fPIC表示使用地址无关代码奇数来生产输出文件 .PHONY:clean clean: rm main libadd.so
当我们生成可执行文件后,可使用ldd命令查看该可执行文件所依靠的动态库。
前面提到windows和Linux下库文件的后缀不同,更根本的原因在于二者文件格式都不同。可以通过file一个动态库查看Linux下动态库的文件类型其实是ELF格式。ELF动态链接文件被称为动态共享对象(DSO,Dynamic Shared Objects),简称共享对象;在windows下,动态链接文件被称为动态链接库(Dynamic Linking Library),也就是.dll文件后缀的全称。
优点:
①毋庸置疑的就是节省内存;
②减少物理页面的换入换出;
③在升级某个模块时,理论上只需要将对应旧的目标文件覆盖掉即可。新版本的目标文件会被自动装载到内存中并且链接起来;
④程序在运行时可以动态的选择加载各种程序模块,实现程序的扩展。
四、静态库和动态库的区别
1. 静态库
这类库的名字一般是 libxxx.a ;利用静态函数库编译成的文件比较大,因为整个 函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。当然这也会成为他的缺点,因为 如果静态函数库改变了,那么你的程序必须重新编译 。
2. 动态库
这类库的名字一般是 libxxx.so ;相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。 动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。
相关推荐:《Linux视频教程》
以上是linux下靜態連結函式庫和動態連結函式庫的差別是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!