天天看點

VC中靜态連結庫和動态連結庫的讨論

1.背景

軟體開發基于子產品化開發的理念,可以提高代碼重用性、便于子產品的測試和子產品功能的維護擴充、縮短開發周期。

子產品化開發在設計上的展現是子產品功能的劃分和子產品之間内聚性、耦合性的設計。在開發技術上的展現主要是動态連結庫和靜态連結庫的設計。

因為設計上功能需要和開發的項目密切聯系,本文不加讨論。

本文主要介紹在開發技術上的展現:即介紹動态連結庫和靜态連結庫。

2.概念和差別

不論是動态連結庫還是靜态連結庫,都是對代碼封裝編譯生成的功能子產品,這類子產品不能單獨執行,需要有exe執行檔案調用。其代碼也不可見,留有功能接口,供二次開發人員使用。

示意圖如下:

上圖隻是簡單的架構示意圖,實際根據連結庫的不同,調用方法也不同。

下面分别對靜态和動态連結庫做簡單介紹。

2.1靜态連結庫

靜态連結庫的字尾名一般是.lib檔案,如果你的可執行程式調用了靜态連結庫,那麼編譯後靜态連結庫中的代碼就要連結到你的可執行程式中去,成為你可執行程式的一部分。是以調用了靜态連接配接的可執行檔案一般比較大一些。

2,2動态連結庫

動态連結庫是相對于靜态連結庫而言的,動态連結庫檔案的擴充名一般是dll,也有可能是drv、sys等。如果一個應用程式使用了動态連結庫,Win32系統保證記憶體中隻有DLL的一份複制品,這是通過記憶體映射檔案實作的。DLL首先被調入Win32系統的全局堆棧,然後映射到調用這個DLL的程序位址空間。

Visual C++支援三種DLL,它們分别是Non-MFC DLL(非MFC動态庫)、MFC Regular DLL(MFC規則(正常)DLL)、MFC Extension DLL(MFC擴充DLL)。

非MFC動态庫不采用MFC類庫結構,其導出函數為标準的C接口,能被非MFC或MFC編寫的應用程式所調用(比如被vb、delphi調用);MFC規則DLL 包含一個繼承自CWinApp的類,無消息循環,可以導出函數,單不能導出類,可以被其他編成語言使用。MFC擴充DLL采用MFC的動态連結版本建立,它隻能被用MFC類庫所編寫的應用程式所調用。

2.3動态連結庫和靜态連結庫的差別

靜态連結庫與動态連結庫都是共享代碼的方式,如果采用靜态連結庫,則無論你願不願意,lib 中的指令都全部被直接包含在最終生成的 EXE 檔案中了。但是若使用 DLL,該 DLL 不必被包含在最終 EXE 檔案中,EXE 檔案執行時可以“動态”地引用和解除安裝這個與 EXE 獨立的 DLL 檔案。靜态連結庫和動态連結庫的另外一個差別在于靜态連結庫中不能再包含其他的動态連結庫或者靜态庫,而在動态連結庫中還可以再包含其他的動态或靜态連結庫。

3.靜态連結庫的建立、釋出及調用

3.1靜态連結庫的建立

在靜态庫中,函數和資料被編譯進一個二進制檔案(通常擴充名為*.LIB),Visual C++的編譯器在處理程式代碼時将從靜态庫中恢複這些函數和資料并把他們和應用程式中的其他子產品組合在一起生成可執行檔案。這個過程稱為"靜态連結",此時因為應用程式所需的全部内容都是從庫中複制了出來,是以靜态庫本身并不需要與可執行檔案一起發行。

Vc中建立靜态連結庫步驟如下:

1、選擇菜單:File-New,打開New對話框。

2、選擇projects屬性頁,左邊清單中選擇 win32 static library,然後再右邊的project name中輸入工程名稱、在location中輸入路徑,如下圖:

點ok,進入下一步,選擇合适的選擇,既可以完成該工程架構。

3、在該工程的頭檔案和代碼檔案中加入需要的功能,編譯後就可以得到靜态連結庫檔案(mathlib.lib)。

3.2靜态連結庫的釋出

靜态連結庫編譯成功後,如果讓其他開發人員使用,最少需要提供2個檔案,即靜态庫的頭檔案和靜态庫lib檔案。當然,成熟的靜态庫還應該提供說明檔案(包含開發人員、日期、庫功能介紹及庫對外的接口等),以友善二次開發人員使用。

3.3靜态連結庫的調用

要調用靜态連結庫,前提條件是必須先擁有庫檔案(.lib)和頭檔案,具體使用方法如下:

方法1:把庫檔案加入到目前工程中,在使用庫中功能的代碼檔案中加入其頭檔案既可以調用庫中的函數。

方法2:項目設定中引用.lib,project-setting-link-object/library modules中添加.lib,在使用庫中功能的代碼檔案中加入其頭檔案既可以調用庫中的函數。

方法3:在使用庫中功能的代碼檔案中加入其頭檔案,并且在加入語句:#pragma comment(lib,"..//bin//mathlib.lib"),保證路徑正确,然後既可以調用庫中函數。

因為靜态連結庫是将全部指令都包含入調用程式生成的EXE檔案中。是以如果用的是靜态連結庫,那麼也就不存在“導出某個函數提供給使用者使用”的情況。

4.動态連結庫的建立、釋出及調用。

4.1動态連結庫的建立

動态連結庫建立(nomfc)

4.2動态連結庫的釋出

4.3動态連結庫的調用

對于動态連結庫:

動态連結庫的使用需要庫的開發者提供生成的.lib檔案和.dll檔案。或者隻提供dll檔案。

首先我們必須先注意到DLL内的函數分為兩種: 

(1)DLL 導出函數,可供應用程式調用; 

(2)DLL 内部函數,隻能在 DLL 程式使用,應用程式無法調用它們。

是以調用程式若想調用DLL中的某個函數就要以某種形式或方式指明它到底想調用哪一個函數。

第一:如何調用?即調用的方式

第二:不同調用方式對應的庫的生成過程和調用規則

第一,存在兩種調用方式——動态調用和靜态調用

第二,兩種調用方式的庫的生成過程和調用規則

1〉動态調用

生成庫的.h頭檔案中的聲明格式如下:

extern "C" 函數傳回類型 __declspec(dllexport) 函數名(參數表);

在調用程式的.cpp源代碼檔案中按如下流程調用:

在main函數代碼的開始處

定義需要的DLL子產品的句柄和此DLL子產品子產品中需要調用的函數的函數指針。

定義好後緊接着就是标準的三部曲:

取得需要的DLL子產品------>傳回子產品句柄

LoadLibrary("DLL子產品路徑")

取得需要的函數位址———>傳回函數指針GetProcAddress(子產品句柄,"函數名")

從記憶體中解除安裝DLL子產品———>FreeLibrary(子產品句柄)

2>靜态調用

在調用程式的.cpp源代碼檔案中按如下流程調用:

#include.........

告訴編譯器與 DLL 相對應的.lib 檔案所在的路徑及檔案名

#pragma comment(lib,"路徑和檔案名") 

extern "C" 函數傳回類型 _declspec(dllimport) 函數名(參數表)分号

int main()

{

..............

}

是以這裡衍生出兩個問題:

我逐漸展開問題。