windows下lib 和 dll 的區別、生成以和使用詳解
首先介紹一下靜態庫(靜態連結庫)、動態庫(動態連結庫)的概念,首先兩者都是程式碼共享的方式。
靜態庫:在連結步驟中,聯結器將從庫檔案取得所需的程式碼,複製到生成的可執行檔案中,這種庫稱為靜態庫,其特點是可執行檔案中包含了庫程式碼的一份完整拷貝;缺點就是被多次使用就會有多份冗餘拷貝。即靜態庫中的指令都全部被直接包含在最終生成的 EXE 檔案中了。在vs中新建生成靜態庫的工程,編譯生成成功後,只產生一個.lib檔案
動態庫:動態連結庫是一個包含可由多個程式同時使用的程式碼和資料的庫,DLL不是可執行檔案。動態連結提供了一種方法,使程序可以呼叫不屬於其可執行程式碼的函式。函式的可執行程式碼位於一個 DLL 中,該 DLL 包含一個或多個已被編譯、連結並與使用它們的程序分
那麼上述靜態庫和動態庫中的lib有什麼區別呢?
靜態庫中的lib:該LIB包含函式程式碼本身(即包括函式的索引,也包括實現),在編譯時直接將程式碼加入程式當中
動態庫中的lib:該LIB包含了函式所在的DLL檔案和檔案中函式位置的資訊(索引),函式實現程式碼由執行時載入在程序空間中的DLL提供
總之,lib是編譯時用到的,dll是執行時用到的。如果要完成原始碼的編譯,只需要lib;如果要使動態連結的程式執行起來,只需要dll。
以下例子均在vs2010上測試
生成和使用動態庫
生成動態庫
新建專案--win32專案--填寫專案名--確定--下一步--應用程式型別:選擇dll--附加選項:選擇匯出符號--完成
可以看到生成了一個dllmain.cpp 檔案,這是dll應用程式的入口,注意它和普通工程的入口main函式不同,這個檔案我們不需要修改。
在這個動態庫中我們舉例匯出一個變數,一個類,一個函式,標頭檔案dll.h如下:
1 //新建生成dll的工程時,vs預設定義了巨集DLL_EXPORT,因此,DLL_API 是 __declspec(dllexport),用來匯出 2 //當我們在靜態呼叫dll時,我們包含該標頭檔案,由於沒有定義DLL_EXPORT,所以DLL_API是 3 //__declspec(dllimport),用來匯入 4 #ifdef DLL_EXPORTS 5 #defineDLL_API __declspec(dllexport) 6 #else 7 #define DLL_API __declspec(dllimport) 8 #endif 9 10 // 匯出類 11 class DLL_API Cdll { 12 public: 13 Cdll(void); 14 // TODO: 在此新增您的方法。 15 }; 16 17 //匯出變數,變數在.cpp檔案中定義 18 extern DLL_API int ndll; 19 20 //匯出函式,加extern "C",是為了保證編譯時生成的函式名不變,這樣動態呼叫dll時才能 21 //正確獲取函式的地址 22 extern "C" DLL_API int fndll(void);
dll.cpp 檔案如下:
1 #include "dll.h" 2 3 4 // 這是匯出變數的一個示例 5 DLL_API int ndll=6; 6 7 // 這是匯出函式的一個示例。 8 DLL_API int fndll(void) 9 { 10 return 42; 11 } 12 13 // 這是已匯出類的建構函式。 14 // 有關類定義的資訊,請參閱 dll.h 15 Cdll::Cdll() 16 { 17 return; 18 }
呼叫動態庫
有兩種方法呼叫動態庫,一種隱式連結,一種顯示連結。
呼叫動態庫:隱式連結
隱式連結 需要.h檔案,dll檔案,lib檔案
(1)將dll放到工程的工作目錄
(2)設定專案屬性--vc++目錄--庫目錄為lib所在的路徑
(3)將lib新增到專案屬性--連結器--輸入--附加依賴項(或者直接在原始碼中加入#pragma comment(lib, “**.lib”))
(4)在原始檔中新增.h標頭檔案
然後就像平常一樣呼叫普通函式、類、變數
呼叫動態庫:顯示連結
顯示呼叫主要使用WIN32 API函式LoadLibrary、GetProcAddress,舉例如下:
1 typedef int (*dllfun)(void);//定義指向dll中函式的函式指標 2 HINSTANCE hlib = LoadLibrary(".\\dll.dll"); 3 if(!hlib) 4 { 5 std::cout<<"load dll error\n"; 6 return -1; 7 } 8 dllfun fun = (dllfun)GetProcAddress(hlib,"fndll"); 9 if(!fun) 10 { 11 std::cout<<"load fun error\n"; 12 return -1; 13 } 14 fun();
生成和使用靜態庫
生成靜態庫
新建專案--win32專案--填寫專案名--確定--下一步--應用程式型別:選擇靜態庫
靜態庫專案沒有main函式,也沒有像dll專案中的dllmain。
建立專案後新增.h檔案,新增相應的匯出函式、變數或類,如下所示
1 #ifndef _MYLIB_H_ 2 #define _MYLIB_H_ 3 4 void fun(int a); 5 6 extern int k; 7 8 class testclass 9 { 10 public: 11 testclass(); 12 void print(); 13 }; 14 15 #endif
.cpp檔案如下
1 #include "stdafx.h" 2 #include "lib.h" 3 #include <iostream> 4 5 void fun(int a) 6 { 7 std::cout<<a<<"lib gen\n"; 8 } 9 10 int k = 222; 11 12 testclass::testclass() 13 { 14 std::cout<<"123\n"; 15 } 16 17 void testclass::print() 18 { 19 std::cout<<"this is testcalss\n"; 20 }
編譯工程後就會生成一個.lib檔案
使用靜態庫
需要.h檔案,lib檔案
(1)設定專案屬性--vc++目錄--庫目錄為lib所在的路徑
(2)將lib新增到專案屬性--連結器--輸入--附加依賴項(或者直接在原始碼中加入#pragma comment(lib, “**.lib”))
(3)在原始檔中新增.h標頭檔案
然後就像平常一樣呼叫普通函式、類、變數,舉例如下:
1 #include <iostream> 2 #include "lib.h" 3 4 #pragma comment(lib, "lib.lib") 5 6 int main() 7 { 8 fun(4); 9 std::cout<<k<<std::endl; 10 testclass tc; 11 tc.print(); 12 return 0; 13 }