Windows的靜態庫與動態庫

Windows的靜態庫與動態庫

1.靜態庫

1.1 靜態庫特點

  • 運行不存在
  • 靜態庫源碼被鏈接到調用程式中
  • 目標程式的歸檔

1.2 C語言靜態庫

  • C靜態庫的創建
    • 創建一個靜態庫項目。
    • 添加庫程式,源文件使用C文件。
int Clib_add(int add1,int add2){
	return add1+add2;
}

int Clib_sub(int sub1,int sub2){
	return sub1 - sub2;
}
  • C靜態庫的使用
    • 庫路勁設置:可以使用pragma關鍵字設置
    • pragma comment(lib,”../lib/clib.lib”)

#pragma comment(lib,"../Debug/Clib.lib")
#include <stdio.h>
#include <process.h>
int main(){
	int sum,sub;
	sum = Clib_add(5,3);
	sub = Clib_sub(5,3);

	printf("sum=%d,sub=%d\n",sum,sub);
	system("pause");
	return 0;
}

1.3 C++語言靜態庫

  • C++靜態庫的創建
    • 創建一個靜態庫項目
    • 添加庫程式,源文件使用cpp文件
int CPPlib_add(int add1,int add2){
	return add1 + add2;
}

int CPPlib_sub(int sub1,int sub2){
	return sub1 - sub2;
}
  • C++靜態庫的使用
    • 庫路徑設置:可以使用pragma關鍵字設置
    • pragma comment(lib,”../lib/cpplib.lib”)

#include <iostream>
using namespace std;
//給鏈接器看
int CPPlib_add(int add1,int add2);
int CPPlib_sub(int sub1,int sub2);
//給編譯器看
#pragma comment(lib,"../Debug/CPPlib.lib") //?CPPlib_add@@YAHHH@Z / ?CPPlib_sub@@YAHHH@Z

extern "C" int Clib_add(int add1,int add2);
extern "C" int Clib_sub(int sub1,int sub2);
#pragma comment(lib,"../Debug/Clib.lib") //Clib_add / Clib_sub
int main(){
	//調c++庫函數
	int sum = CPPlib_add(5,4);  //?CPPlib_add@@YAHHH@Z
	int sub = CPPlib_sub(5,4);  //?CPPlib_sub@@YAHHH@Z
	cout << "sum=" << sum << ",sub=" << sub << endl;
	
	//調c庫函數
	sum = Clib_add(5,3);  //?Clib_add@@YAHHH@Z 使用extern "C",編譯時不換函數名-->Clib_add
	sub = Clib_sub(5,3);  //?Clib_sub@@YAHHH@Z                                -->Clib_sub
	cout << "sum=" << sum << ",sub=" << sub << endl;
	system("pause");
	return 0;
}

2.動態庫

2.1 動態庫特點

  • 動態庫的特點

    • 運行時獨立存在
    • 源碼不會鏈接到執行程式
    • 使用時載入(使用動態庫必須使動態庫執行)
  • 與靜態庫的比較

    • 由於靜態庫是將程式碼嵌入到使用程式中,多個程式使用時,會有多分程式碼,所以程式碼體積會增大。動態庫的程式碼只需要存在一份,其他程式通過函數地址使用,所以程式碼體積小。

    • 靜態庫發生變化後,新的程式碼需要重新鏈接嵌入到執行程式中。動態庫發生變化後,如果庫中函數的定義(或地址)未變化,其他使用DLL的程式不需要重新鏈接。

2.2動態庫創建

  • 創建動態庫項目

  • 添加庫程式

  • 庫程式導出 – 提供給使用者庫中的函數等資訊。

    • 聲明導出:使用_declspec(dllexport)導出函數

    注意:動態庫編譯鏈接後,也會有LIB文件,是作為動態庫函數映射使用,與靜態庫不完全相同。

    製作動態庫

    _declspec(dllexport) int CPPdll_add(int add1,int add2){
    	return add1 + add2;
    }
    
    _declspec(dllexport) int CPPdll_sub(int sub1,int sub2){
    	return sub1 - sub2;
    }
    
    _declspec(dllexport) int CPPdll_mul(int mul1,int mul2){
    	return mul1 * mul2;
    }
    

    動態庫原理圖

    image-20210618214016382

    • 模組定義文件:.def

    例如:LIBRARY DLLFunc //庫

    ​ EXPORTS //庫導出表

    ​ DLL_Mul @1 //導出的函數

    不加聲明導出

    int CPPdll_add(int add1,int add2){
    	return add1 + add2;
    }
    
    int CPPdll_sub(int sub1,int sub2){
    	return sub1 - sub2;
    }
    
    int CPPdll_mul(int mul1,int mul2){
    	return mul1 * mul2;
    }
    

    添加模組定義導出文件

    LIBRARY	CPPDll
    EXPORTS
    	CPPdll_add @1
    	CPPdll_sub @2
    	CPPdll_mul @3
    

2.3動態庫的使用

  • 隱式鏈接(作業系統負責使動態庫執行)

    1. 頭文件和函數原型

      ​ 可以在函數原型的聲明前,增加_declspec(dllimport)

    2. 導入動態庫的LIB文件

    3. 在程式中使用函數

    4. 隱式鏈接的情況,dll文件可以存放的路徑:

      • 與執行文件中同一個目錄下(建議放在此目錄下)
      • 當前工作目錄
      • Windows目錄
      • Windows/System32目錄
      • Windows/System
      • 環境變數PATH指定目錄
    #include <iostream>
    using namespace std;
    
    _declspec(dllimport)int CPPdll_add(int add1,int add2);
    _declspec(dllimport)int CPPdll_sub(int sub1,int sub2);
    _declspec(dllimport)int CPPdll_mul(int mul1,int mul2);
    //通知鏈接器到哪抓編號和dll文件名(CPPDll.dll)
    #pragma comment(lib,"../Debug/CPPDll.lib")
    
    int main(){
    	int sum = CPPdll_add(5,4);
    	int sub = CPPdll_sub(5,4);
    	int mul = CPPdll_mul(5,4);
    	cout << "sum=" << sum << ",sub=" << sub << ",mul=" << mul << endl;
    	system("pause");
    	return 0;
    }
    
  • 顯示鏈接(程式設計師自己負責使動態庫執行)

    1. 定義函數指針類型 typedef

    2. 載入動態庫

      HMODULE LoadLibrary(
      	LPCTSTR lpFileName //動態庫文件名或全路勁
      ); //返回DLL的實例句柄(HINSTANCE)
      
    3. 獲取函數地址

      FARPROC GetProcAddress(
      	HMODULE hModule  //DLL句柄
          LPCSTR lpProcName //函數名稱
      ); //成功返回函數地址
      
    4. 使用函數

    5. 卸載動態庫

      BOOL FreeLibrary(
      	HMODULE hModule //DLL的實例句柄
      );
      
    #include <iostream>
    #include <Windows.h>
    using namespace std;
    
    typedef int(*FUNC)(int m,int n);
    int main(){
    	HINSTANCE hDll = LoadLibrary("CPPDll.dll");
    	cout << "hDll:" << hDll << endl;
    
    	FUNC add = (FUNC)GetProcAddress(hDll,"CPPdll_add");
    	cout << "addAdress:" << add << endl;
    	int sum = add(5,4);
    	cout << "sum:" << sum << endl;
    
    	FUNC sub = (FUNC)GetProcAddress(hDll,"CPPdll_sub");
    	cout << "subAdress:" << sub << endl;
    	int su = sub(5,4);
    	cout << "sub:" << su << endl;
    
    	FUNC mul = (FUNC)GetProcAddress(hDll,"CPPdll_mul");
    	cout << "mulAdress:" << mul << endl;
    	int mu = mul(5,4);
    	cout << "mul:" << mu << endl;
    
    	system("pause");
    	FreeLibrary(hDll);
    	return 0;
    }
    

2.4動態庫中封裝類

  • 在類名稱前增加_declspec(dllexport)定義,例如:

    class _declspec(dllexport) CMath{
        ...
    };
    
  • 通常使用預編譯開關切換類的導入導出定義,例如:

    #ifdef DLLCLASS_EXPORTS
    #define EXT_CLASS _declspec(dllexport)  //dll
    #else
    #definE EXT_CLASS _declspec(dllimport) //使用者
    #endif
    
    class EXT_CLASS CMath{
        ...
    };
    

    例子:

    頭文件

    #ifndef _ClASSDLL_H
    #define _CLASSDLL_H
    
    #ifdef DLLCLASS_EXPORTS
    #define EXT_CLASS _declspec(dllexport)  //dll
    #else
    #define EXT_CLASS _declspec(dllimport) //使用者
    #endif
    
    class EXT_CLASS CMath{
    public:
    	int add(int m,int n);
    	int sub(int m, int n);
    };
    
    #endif
    

    源文件

    #define DLLCLASS_EXPORTS
    #include "ClassDll.h"
    
    int CMath::add(int m,int n){
    	return m + n;
    }
    
    int CMath::sub(int m,int n){
    	return m - n;
    }
    

    調用動態庫中的封裝類

    #include "..\ClassDll\ClassDll.h"
    #include <iostream>
    using namespace std;
    #pragma comment(lib,"../Debug/ClassDll.lib")
    
    int main(){
    	CMath myMath;
    	int sum = myMath.add(5,4);
    	int sub = myMath.sub(5,4);
    	cout << "sum=" << sum << ",sub=" << sub << endl;
    	system("pause");
    	return 0;
    }
    
Tags: