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