静态链接库和动态链接库(转)
我們可以創(chuàng)建一種文件里面包含了很多函數(shù)和變量的目標(biāo)代碼,鏈接的時候只要把這個文件指示給鏈接程序就自動地從文件中查找符合要求的函數(shù)和變量進(jìn)行鏈接,整個查找過程根本不需要我們操心。
這個文件叫做 “庫(Libary)”,平時我們把編譯好的目標(biāo)代碼存儲到“庫”里面,要用的時候鏈接程序幫我們從庫里面找出來。
靜態(tài)鏈接庫:
在早期庫的組織形式相對簡單,里面的目標(biāo)代碼只能夠進(jìn)行靜態(tài)鏈接,所以我們稱為“靜態(tài)庫”,靜態(tài)庫的結(jié)構(gòu)比較簡單,其實(shí)就是把原來的目標(biāo)代碼放在一起,鏈接程序根據(jù)每一份目標(biāo)代碼的符號表查找相應(yīng)的符號(函數(shù)和變量的名字),找到的話就把該函數(shù)里面需要定位的進(jìn)行定位,然后將整塊函數(shù)代碼放進(jìn)可執(zhí)行文件里,若是找不到需要的函數(shù)就報錯退出。
靜態(tài)庫的兩個特點(diǎn):
#1鏈接后產(chǎn)生的可執(zhí)行文件包含了所有需要調(diào)用的函數(shù)的代碼,因此占用磁盤空間較大。
#2如果有多個(調(diào)用相同庫函數(shù)的)進(jìn)程在內(nèi)存中同時運(yùn)行,內(nèi)存中就存有多份相同的庫函數(shù)代碼,因此占用內(nèi)存空間較多。
動態(tài)鏈接庫:
動態(tài)鏈接庫就是為了解決這些問題而誕生的技術(shù),顧名思義,動態(tài)鏈接的意思就是在程序裝載內(nèi)存的時候才真正的把庫函數(shù)代碼鏈接進(jìn)行確定它們的地址,并且就算有幾個程序同時運(yùn)行,內(nèi)存也只存在一份函數(shù)代碼。
動態(tài)庫的代碼必須滿足這樣一種條件:能夠被加載到不同進(jìn)程的不同地址,所以代碼要經(jīng)過特別的編譯處理,我們把這種經(jīng)過特別處理的代碼叫做“位置無關(guān)代碼(Position independed Code .PIC)”.
根據(jù)載入程序何時確定動態(tài)代碼的邏輯地址,可以把動態(tài)裝載分為兩類。
#1 靜態(tài)綁定(static binding)
使用靜態(tài)綁定的程序一開始載入內(nèi)存的時候,載入程序就會把程序所有調(diào)用到的動態(tài)代碼的地址算出確定下來,這種方式使程序剛運(yùn)行的初始化時間較長,不過旦完成動態(tài)裝載,程序的運(yùn)行速度就很快。
#2動態(tài)綁定(dynamic binding)
使用這種方式的程序并不在一開始就完成動態(tài)鏈接,而是直到真正調(diào)用動態(tài)庫代碼時,載入程序才計算(被調(diào)用的那部分)動態(tài)代碼的邏輯地址,然后等到某個時候,程序又需要調(diào)用另外某塊動態(tài)代碼時,載入程序又去計算這部分代碼的邏輯地址,所以,這種方式使程序初始化時間較短,但運(yùn)行期間的性能比不上靜態(tài)綁定的程序。
平時默認(rèn)進(jìn)行鏈接的標(biāo)準(zhǔn) C/C++ 函數(shù)就是動態(tài)庫。
Note:
內(nèi)存中的動態(tài)代碼只有一份副本,但動態(tài)庫的數(shù)據(jù)仍然可能有多份副本,因?yàn)槊恳粋€鏈接到動態(tài)的進(jìn)程都可能會修改庫的數(shù)據(jù),每當(dāng)出現(xiàn)這種情況的時候,操作系統(tǒng)就復(fù)制出一份數(shù)據(jù)副本,然后修改進(jìn)程的地址空間映射,使它指向新的數(shù)據(jù)副本,于是進(jìn)程最后修改的只是屬于自己的那份數(shù)據(jù)。
一、如何使用靜態(tài)鏈接庫?
1. .h和.lib放到你工程目錄下面
2.在stdafx.h里面,加入
#include "xxx.h"
#pragma comment(lib,"xxx.lib")
二、動態(tài)鏈接庫轉(zhuǎn)換為靜態(tài)鏈接庫?
?? > cd /c/usr/src/lib
?? > pexports.exe ../bin/iconv.dll > iconv.def
?? > dlltool.exe -e libiconv.exp -l libiconv.a -D iconv.dll -d iconv.def -z libiconv.def -k -v
?? > ranlib libiconv.a
動態(tài).dll -> 靜態(tài).lib:
使用DLL to Lib工具轉(zhuǎn)換,此工具收費(fèi)。
動態(tài).dll _> 動態(tài).lib:
使用VC的lib.exe工具,可以由.DLL生成.Lib
?三、C 靜態(tài)鏈接庫LIB的制作?
要創(chuàng)建靜態(tài)庫,選擇File->New菜單,彈出New對話框。選擇Projects標(biāo)簽,在項目類型列表框中選擇Win32 Static Library,在Name中輸入mymath,表明要創(chuàng)建一個mymath.lib的靜態(tài)庫文件。
然后用Project->Add to Project->Files菜單往mymath工程中加入以下兩個文件:
//MyLib.h
#ifndef _MYMATH_H
#define _MYMATH_H
extern "C"
{
?int Summary(int n);
}
#endif
//MyLib.c
extern "C" int Summary(int n)
{
?return n+2;
}
//編譯程序
//使用
#i nclude "MyLib.h"
LIB MyLib.lib
就可以使用導(dǎo)出的函數(shù)
四、如何在VC.NET中制作并使用動態(tài)鏈接庫DLL?
1、將C++類做成DLL
建立一個MFC DLL工程,PacketTransfer;將類的頭文件搞到PacketTransfer.h中,并在要在外部調(diào)用的類聲明前加_declspec(dllexport),如:要在外內(nèi)調(diào)用CPacketTransfer類,可對該類做聲明:
class _declspec(dllexport) CPacketTransfer
{
……
};
將類的定義文件內(nèi)容拷到Sample.cpp中,然后生成該工程,生成的文件有:PacketTransfer.dll和PacketTransfer.lib
2、調(diào)用DLL中的C++類
將PacketTransfet.h,PacketTransfer.dll和PacketTransfer.lib拷貝到要調(diào)用的工程目錄下,在工程屬性中加入輸入:PacketTransfer.lib,并包含頭文件PacketTransfer.h,就可以使用類CPacketTransfer了:
CPacketTransfer temp,*pTest;……
3、將C或C++函數(shù)接口做成DLL
??? 建立一個MFC DLL工程,api;將用到的頭文件聲明拷貝加到api.h中,將其它代碼拷到api.cpp中,并在所有要調(diào)用的接口函數(shù)聲明前加入導(dǎo)出聲明,如:
extern "C" _declspec(dllexport) bool MakeMD5File(char *file,char *key);
??? 然后生成該工程,得到文件api.dll和api.lib
4、使用DLL中的接口
將api.dll和api.lib拷到工程目錄下,在工程屬性中加入輸入:api.lib,然后在使用接口函數(shù)前用extern "C" _declspec(dllimport)聲明該接口即可:
extern "C" _declspec(dllimport) bool MakeMD5File(char *file,char *key);
??? 然后可以使用該函數(shù)的,也可以用LoadLibrary()等系統(tǒng)API直接調(diào)用DLL中的接口.
?五、使用動態(tài)鏈接庫DLL的方法?
我們可以把 .dll 文件想象成 .c 或 .cpp 文件,
函數(shù)的主體在這個文件中,而函數(shù)的定義在 .h 文件中,
我們把 .lib 文件想象成 .dll 中函數(shù)的聲明,
因此,只要把 .h, .lib, .dll 三個文件安排好,
讓你的程序能找到它們就可以像使用自己寫的函數(shù)一樣適用 .dll 中的函數(shù)了。
具體方法如下:
1、建立一個簡單的C程序
2、添加想要使用的 .dll 中的函數(shù)(這是opencv庫中的功能)
?? 此時會提示有錯誤,沒有任何代碼,就是用函數(shù)和結(jié)構(gòu)體,當(dāng)然會告訴你沒定義了;-)
3、將 .h 文件拷貝過來
? 至于你應(yīng)該拷貝哪個 .h 文件,你自己必須知道,就是那個 .dll 文件對應(yīng)的 .h 文件
? 現(xiàn)在編譯后錯誤少了兩個,確切的說應(yīng)該是錯誤都去掉了,多了一個新錯誤,說沒有cxcore.h文件
? 這是拷貝過來的highgui.h文件需要的,我們來看看,
? 看到了吧,就是說這個文件必須引用另一個文件。
? 真實(shí)情況是這樣的:這個 .dll 文件需要另一個 .dll 文件的支持,我們?nèi)绨l(fā)泡制,也把頭文件拷貝過來
? 又出現(xiàn)一個新的錯誤,缺少cxtypes.h文件,這是剛拷貝來的cxcore.h文件需要的,我們繼續(xù)拷貝
??
4、 注意啦!要看看錯誤的類型,已經(jīng)不是編譯錯誤啦,而是連接錯誤,說明語法已經(jīng)沒有錯誤,是缺少函數(shù)的實(shí)體了。
? 現(xiàn)在的情況就相當(dāng)于我們已經(jīng)在 .h 文件中定義了調(diào)用的函數(shù),但是沒有給出函數(shù)實(shí)體。我們把函數(shù)實(shí)體 .dll 文件
? 拷貝過來。應(yīng)該拷貝的 .dll 文件,你自己應(yīng)該知道,如果不知道,sorry,錯啦
? 剛才的錯誤是連接錯誤,這個時候它找的是函數(shù)的聲明,因?yàn)?.dll 文件只有在運(yùn)行時才會涉及到。為了證明這一點(diǎn),
? 我們把剛拷貝來的 .dll 文件都刪除。然后把 .lib 文件拷貝來
? 為什么還有錯誤? 因?yàn)槟悴]有告訴程序應(yīng)該連接它,怎么樣,沒有任何錯誤了吧。我們運(yùn)行看看
? 這就是運(yùn)行時錯誤了,因?yàn)闆]有可用的 .dll 文件,因此提示錯誤,按照它提示的 .dll 文件,我們把它拷貝過來。
? 又提示了一個新的錯誤,缺少另一個 .dll文件,我說過了,前面的那個 .dll文件需要后面的這個支持.
? 這回運(yùn)行出來了.
?六、VC++中使用靜態(tài)鏈接庫和動態(tài)鏈接庫小結(jié)?
最近在VC++使用GSL(GNU科學(xué)計算庫)靜態(tài)庫和動態(tài)庫時遇到了一些問題,做個小結(jié),以備參考。
?????? 靜態(tài)庫包括.lib和.h文件,在工程中使用靜態(tài)庫分為3步:
1在工程中加入靜態(tài)庫,有兩種方法:
方法一:項目設(shè)置中引用.lib,project-setting-link-object/library modules中添加.lib;(需要在tools/options設(shè)置正確的引用路徑)
方法二:在項目中直接加入lib,project-add to project-files,選擇正確的.lib。
2在工程中包括.h文件;(可能 需要在tools/options設(shè)置正確的引用路徑)
3在工程中使用靜態(tài)庫中的函數(shù);--大功告成!
?????? 動態(tài)鏈接庫一般包括.lib(導(dǎo)出函數(shù)),.h,.dll,使用動態(tài)庫有兩種情況:
1隱式鏈接,同使用靜態(tài)庫相似,分為三步:引用.lib,包含頭文件,使用導(dǎo)出函數(shù);
2動態(tài)加載,直接使用LoadLibrary 加載所需的動態(tài)庫,然后指定所需的導(dǎo)出函數(shù),效率最高!
七、為什么要使用動態(tài)鏈接庫(DLL)?
提起DLL您一定不會陌生,在Windows中有著大量的以DLL為后綴的文件,它們是保證Windows正常運(yùn)行和維護(hù)升級的重要保證。(舉個例子,筆者的Win95 System目錄下盡有500多個DLL文件。)其實(shí),DLL是一種特殊的可執(zhí)行文件。說它特殊主要是因?yàn)橐话闼疾荒苤苯舆\(yùn)行,需要宿主程序比如*.EXE程序或其他DLL的動態(tài)調(diào)用才能夠使用。簡單的說,在通常情況下DLL是經(jīng)過編譯的函數(shù)和過程的集合。
使用DLL技術(shù)主要有以下幾個原因:
1、減小可執(zhí)行文件大小。
??? DLL技術(shù)的產(chǎn)生有很大一部分原因是為了減小可執(zhí)行文件的大小。當(dāng)操作系統(tǒng)進(jìn)入Windows時代后,其大小已經(jīng)達(dá)到幾十兆乃至幾百兆。試想如果還是使用DOS時代的單執(zhí)行文件體系的話一個可執(zhí)行文件的大小可能將達(dá)到數(shù)十兆,這是大家都不能接受的。解決的方法就是采用動態(tài)鏈接技術(shù)將一個大的可執(zhí)行文件分割成許多小的可執(zhí)行程序。
2、實(shí)現(xiàn)資源共享。
??? 這里指的資源共享包括很多方面,最多的是內(nèi)存共享、代碼共享等等。早期的程序員經(jīng)常碰到這樣的事情,在不同的編程任務(wù)中編寫同樣的代碼。這種方法顯然浪費(fèi)了很多時間,為了解決這個問題人們編寫了各種各樣的庫。但由于編程語言和環(huán)境的不同這些庫一般都不能通用,而且用戶在運(yùn)行程序時還需要這些庫才行,極不方便。DLL的出現(xiàn)就像制定了一個標(biāo)準(zhǔn)一樣,使這些庫有了統(tǒng)一的規(guī)范。這樣一來,用不同編程語言的程序員可以方便的使用用別的編程語言編寫的DLL。另外,DLL還有一個突出的特點(diǎn)就是在內(nèi)存中只裝載一次,這一點(diǎn)可以節(jié)省有限的內(nèi)存,而且可以同時為多個進(jìn)程服務(wù)。
3、便于維護(hù)和升級。
??? 細(xì)心的朋友可能發(fā)現(xiàn)有一些DLL文件是有版本說明的。(查看DLL文件的屬性可以看到,但不是每一個DLL文件都有)這是為了便于維護(hù)和升級。舉個例子吧,早期的Win95中有一個BUG那就是在閏年不能正確顯示2月29日這一天。后來,Microsoft發(fā)布了一個補(bǔ)丁程序糾正了這個BUG。值得一提的是,我們并沒有重裝Win95,而是用新版本的DLL代替了舊版本的DLL。(具體是哪一個DLL文件筆者一時想不起來了。)另一個常見的例子是驅(qū)動程序的升級。例如,著名的DirectX就多次升級,現(xiàn)在已經(jīng)發(fā)展到了6.0版了。更妙的是,當(dāng)我們試圖安裝較低版本的DLL時,系統(tǒng)會給我們提示,避免人為的操作錯誤。例如我們升級某硬件的驅(qū)動程序時,經(jīng)常碰到Windows提示我們當(dāng)前安裝的驅(qū)動程序比原來的驅(qū)動程序舊。
4、比較安全。
??? 這里說的安全也包括很多方面。比如,DLL文件遭受病毒的侵害機(jī)率要比普通的EXE文件低很多。另外,由于是動態(tài)鏈接的,這給一些從事破壞工作的“高手”們多少帶來了一些反匯編的困難。
總結(jié)
以上是生活随笔為你收集整理的静态链接库和动态链接库(转)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JVM垃圾回收3——参数详解(转载)
- 下一篇: 关于软件质量(2)- 开发 vs 测试