1. 程式人生 > >靜態庫、動態庫,dll檔案、lib檔案,隱式連結、顯式連結淺見

靜態庫、動態庫,dll檔案、lib檔案,隱式連結、顯式連結淺見

靜態連結、動態連結

靜態庫和動態庫分別應用在靜態連結方式和動態連結方式中,所謂靜態連結方式是指在程式執行之前完成所有的連結工作,把靜態庫一起打包合入,生成一個可執行的目標檔案(EXE檔案)。所謂動態連結方式是指可執行目標檔案在執行過程中才去載入呼叫相關功能函式,即在需要時才按需呼叫,是動態使用的。

靜態庫、動態庫、隱式連結和顯示連結中操作物件都是庫,那麼什麼是庫?

庫是已經提前寫好的、現有的,可以複用的程式碼,本質上來說庫是一種經過編譯生成的可執行程式碼的二進位制形式,可以被作業系統載入記憶體執行。庫分為兩種:靜態庫(.a、.lib)動態庫( .so、.dll)

靜態庫和動態庫中的靜態和動態是針對庫連結入程式時不同的處理方式而言的,看一下程式從程式碼編譯成可執行檔案的步驟:


靜態庫

靜態連結中對應靜態庫,在連結階段,會將彙編生成的目標檔案(.o檔案)與引用到的靜態庫(.a、.lib)一起連結打包到可執行檔案,所以靜態看的格式必定跟彙編生成的.o檔案格式相似。可以把靜態庫簡單看成是一組目標檔案(包括.o和.lib檔案)的集合,這些檔案一起經過打包後最終形成一個靜態庫檔案。

靜態庫的特點:採用靜態庫的連結方式把靜態庫中的內容一起連結到可執行檔案中,會導致可執行檔案較大。但是程式編譯好之後不再需要靜態庫了(因為已經完整複製了靜態庫中的內容連結到本體程式設計師中了),移植方便,但這也導致了使用靜態庫的程式的更新升級會比較麻煩,每次微小的改動都需要編譯整個程式重新載入靜態庫,並在客戶端重新安裝整個程式。

動態庫:

動態連結中對應的是動態庫,動態庫在程式編譯時不會被連結到目的碼中,而是直到可執行檔案被執行過程中才被(按需)載入呼叫。

不同的應用程式如果呼叫相同的庫,那麼在記憶體裡只需要有一份該共享的拷貝就可以了,規避了空間浪費問題,動態庫的這種連結方式解決了靜態庫記憶體空間浪費和對程式更新比較麻煩的問題,當程式需要升級更新時,只需要將需要改動升級的模組對應的動態庫傳送給客戶端替換即可,避免了需要重新下載安裝整個程式包的“不能忍”。

動態庫的特點:程式對動態庫的載入是在執行階段,需要同可執行檔案一起釋出和存在。可以實現程序間的資源共享,並用使得程式的更新升級操作變得很簡單。

dll檔案

動態連結庫(Dynamic Link Library,DLL)是Windows系統中實現函式庫共享的一種方式,可以使程序呼叫不屬於其可執行程式碼的函式,dll檔案包含最少一個已被編譯、連結並與使用它們的程序分開儲存的函式。

使用動態連結庫有助於共享資料和資源,多個應用程式可以同時訪問記憶體中單個DLL副本內的函式;把完成不同功能的函式編譯到不同的動態庫中,可以更為方便的對系統指定的模組進行獨立的維護,而不會影響到系統中其他功能模組的正常執行,有助於程式的模組式開發。

lib檔案

lib庫也是一種實現函式共享的方式,分為兩種,一種是靜態連結庫(Static Library/Static link Library),另一種是動態連結庫DLL的匯入庫(Import Library)。

lib分為兩種,一種是靜態庫中的lib,一種是動態庫中的lib 。

靜態連結庫中的lib:Lib裡包含了程式碼本身,在編譯的時候,直接將lib檔案中的程式碼插入到呼叫程式中,在呼叫lib的程式中包含了一份完整的拷貝,一起參與最終程式的編譯。用於生成靜態連結庫lib的程式在編譯後,只會生成一個.lib檔案,不會生成.dll檔案。

動態連結庫中的lib:Lib裡包含了函式所在的dll和dll中函式入口資訊,程式碼由執行時載入在程序空間中的dll提供,用於生成動態連結庫DLL(或lib)的程式在編譯後,會生成兩個檔案,一個是.lib檔案,一個是.dll檔案。

可以簡單的概括為在靜態庫中的lib包含了函式程式碼本身,在編譯時直接嵌入到呼叫程式中;

在動態庫中的lib包含了函式所在的dll檔案和檔案中函式位置的索引,函式實現的程式碼由執行時載入到程序空間中的dll提供。所以可以說lib 是在編譯時用到的,dll是在執行時用到的

隱式連結

隱式連結和顯式連結是dll檔案的兩種不同載入方式。載入dll檔案就是將DLL檔案對映到使用者程序地址空間,就可以在程式執行的時候進行函式呼叫。

隱式連結需要通過lib檔案和.h檔案載入,lib檔案包含了dll允許應用程式匯出的所有函式的符號名和可選的標識號,但是並不含有具體的程式碼實現。隱式連結不需指明DLL檔案的實際儲存路徑,不需關心DLL檔案的實際裝載,而是LIB檔案作為DLL的替代檔案被編譯到應用程式中。連結器檢測到應用程式呼叫了LIB檔案中的某個函式時,就會在應用程式EXE檔案中加入相關資訊。該應用程式執行時,系統會檢視這個檔案的DLL資訊,並將DLL檔案對映到地址空間。

系統執行時會從本地查詢dll檔案,尋找路徑的先後順序是:

  • 1. EXE檔案所在目錄 
  • 2. 當前程式工作目錄 
  • 3. 系統目錄 
  • 4. Windows目錄 
  • 5. 環境變數中所有目錄
VC中隱式連結的方法如下:
  • 1.Property->Linker->Input->Additional Dependencies中新增.lib檔案,或者在原始碼中加入指令#pragma              comment(lib,"XX.lib")
  • 2. Property->Linker->Input->Additional Library Directories中配置.lib檔案所在的相對路徑 
  • 3. 將.dll檔案置入工程所在目錄,然後新增對應的.h標頭檔案,標頭檔案中宣告dll中函式的方式為:                         extern "C"_declspec(dllimport) int FunctionName(int a,int b);

顯式連結


顯示連結不需要用到lib庫,在執行過程中隨時可以載入DLL檔案,也可以隨時解除安裝DLL檔案,這是隱式連結所無法作到的,所以顯式連結具有更好的靈活性,能夠更加有效的使用記憶體,在編寫大型程式時往往使用顯示呼叫。

該方法使用Load Library或者AfxLoadLibrary對DLL進行動態載入;使用GetProcessAdress獲得所呼叫函式的指標;使用完畢後以Free Library或者AfxFreeLibrary將DLL從地址空間中解除安裝。