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;
    }
    

版权声明:本文为muxisuibi原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/muxisuibi/p/14913297.html