差異:1、動態函式庫的字尾為“.so”,靜態函式庫的字尾為“.a”。如果動態函式庫發生變化,程式不需要重新編譯,但如果靜態函式庫變化了,則必須重新編譯程式。 3.相對於靜態函式庫,動態函式庫在編譯的時候並沒有被編譯進目標程式碼中,使用者的程式執行到相關函數時才呼叫該函數函式庫裡的對應函數,因此動態函式庫所產生的可執行文件比較小。
一、函式庫的基礎概念:
在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,那麼當更新任何一項模組時,使用者需要重新下載整個20MB的程式。
三、動態函式庫與動態連結
<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下库文件后缀不同的根本原因是两者文件格式不同。在Linux系统中,我们可以通过使用file命令来检测动态库的文件类型,而其实这些动态库都是以ELF格式存储的。ELF动态链接文件被称为动态共享对象(DSO,Dynamic Shared Objects),简称共享对象;在windows下,动态链接文件被称为动态链接库(Dynamic Linking Library),也就是.dll文件后缀的全称。
优点:
①毋庸置疑的就是节省内存;
②减少物理页面的换入换出;
升级某个模块时,通常只需覆盖对应的旧目标文件。新版本的目标文件会被自动装载到内存中并且链接起来;
④程序在运行时可以动态的选择加载各种程序模块,实现程序的扩展。
四、静态库和动态库的区别
1. 静态库
这类库的名字一般是 libxxx.a ;利用静态函数库编译成的文件比较大,因为整个 函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。如果静态函数库发生更改,那么你的程序需要重新编译,所以这也会成为他的不足之处。
2. 动态库
这类库的名字一般是 libxxx.so ;相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。为使程序能够正常运行,需要在程序的运行环境中提供相应的函数库,因为该库无法被整合进程序,而是在程序运行时动态地申请和调用。动态函数库的更新方便,因为它的修改不会影响你的程序。
以上是linux下靜態連結庫和動態連結庫的差別有哪些的詳細內容。更多資訊請關注PHP中文網其他相關文章!