动态链接和静态链接(转)
前言
DLL無非就是一個『函示庫(Library)』,只是多了"動態"兩個字。那講到這裡相信聰明的人一定想問,那一定也存在著靜態函示庫(Static-Link Library)吧?沒錯!的確是存在的。那既然都是函示庫為什麼又要去區分靜態與動態呢?
- Static-Link Library
- 當程式在Compile-Time時,就會先去檢查所要連結的函示庫是否存在並載入,並一併連結成Object Code。且在程式執行時,每一個用到此函示庫的Process會擁有自己一份Copy,換言之,他沒辦法讓兩個Process共用同一份Copy; 這樣一來對於記憶體資源而言,是比較浪費的。
- Dynamic-Link Library
- DLL比較特別的地方為,程式在Load-Time或Run-Time才會去載入此函示庫,且所有使用到此函示庫的Process會共用同一塊實體記憶體區塊,相對Static-Link Library而言,是比較省記憶體資源的。
DLL function權限
DLL中,function的權限來分類的話,可分為exported function及internal function。從字面來看,很快得知道exported當然就是給使用此DLL的Process來呼叫,反之,internal僅提供給DLL內部呼叫。
DLL 的記憶體管理
每一個Process都會有自己的virtual address space (來自於Virtual memory design),當每一個Process使用相同的DLL,他們會有自己不同的virtual address來指向這個DLL實體位置。於是這個DLL在整個系統之中只會有一份Copy,當然系統也會有自動會收的機制,他會利用Reference count的機制去偵測是否有Process還在使用此DLL,最後一個使用的Process若終止了,那此DLL在實體記憶體中就會被回收了。
DLL建立
範例
#include <iostream>
using namespace std;
#ifdef __cplusplus // If used by C++ code,
extern "C" { // we need to export the C interface
#endif
__declspec(dllexport) int __cdecl myAddition(int pX,int pY)
{
int result = (pX+pY);
cout << "(In DLL)Result: " <<result<< endl;
return result;
}
#ifdef __cplusplus
}
#endif
說明
- __cdecl
- 此為Calling Convention的修飾詞。
Load-time DLL 使用
在使用DLL之前必須先行加入參考此函示庫(import library, .lib file),且當程式在pre-executation時就會先確認所有imported library是否都正確地Load完畢,若程式無法於此刻正確得Load函示庫的話,那程式就無法執行。
範例
#include <iostream>
using namespace std;
extern "C" int __cdecl myAddition(int pX,int pY);
int main()
{
cout << "(In main)Result: " << myAddition(1,2) << endl;
system("PAUSE");
}
執行結果
(In DLL)Result: 3
(In main)Result: 3
Run-time DLL 使用
在使用DLL時,是在程式碼中利用LoadLibrary或LoadLibraryEx將DLL讀到記憶體中,並利用GetProcAddress方法去取得此function pointer。這樣的作法有一個優點,就是程式跑要用到此函示庫的部分,才會去Load,對於Memory的控制是更具有威力的。
Calling convention
主要是用來宣告function在呼叫過程中,如何去管理堆疊(stack)。從機器語言來看,在呼叫一個Funcation前,Caller一定會先將一要傳入Function的參數先存起來,那當Function結束時,並將控制權交還給Caller後,這些被暫存參數之暫存器必須被清空(Stack cleanup)。
那在VS編譯器中,有兩種宣告方式:_cdecl, _stdcall(WINAPI)。_cdecl是將Stack cleanup行為交給Caller來處理,通常當函數傳入參數不是固定時(如:printf()),我們會建議採用_cdecl宣告詞。_stdcall(WINAPI)是由Callee來執行Stack cleaup,這通常是用來呼叫WIN32 API的函示所用的。作者本身大多都是採用_cdecl來宣告我所做的DLL。

浙公网安备 33010602011771号