1. 动态链接库的基本概念
- 动态链接库 (DLL):在运行时加载到内存中的共享库,可以在多个程序中复用,减少程序大小。
- 静态库:在编译时直接链接到目标程序中,生成独立的可执行文件。
2. 创建动态链接库
2.1 动态库项目结构
假设动态MyDll,功能是提供一个add简单函数:
- 创建一个 项目命名 MyDll,新建bing.h和bing.cpp文件。(注意如果新建.h和.cpp文件和项目名称不一样,生成时不会生成.lib文件,需要在cpp文件里实现时候额外添加 extern "C" __declspec(dllexport)标注,如果我新建的为MyDll.h和MyDll.cpp文件就不会有这个问题,原因 不清楚)
- 使用
extern "C"
和__declspec(dllexport)
导出函数。 - 编译生成
MyDll.dll
和对应的MyDll.lib
。
2.2 动态库代码
头文件 (bing
.h):
#pragma once
//宏定义保护机制
#ifndef BING_H
#define BING_H
//C++ 编译器中编译时,会自动定义 __cplusplus 宏,"C"确保动态库的导出符号能被 C语言调用
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
//新建动态库会自动定义MYDLL_EXPORTS 宏,定义MYDLL_API ,用于导出符号
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif //!MYDLL_EXPORTS
MYDLL_API int add(int a, int b); // 加法函数
#ifdef __cplusplus
}
#endif //1__cplusplus
#endif // !BING_H
源文件 (bing.cpp):
#include"bing.h"
#include"pch.h"
// 我的项目名和文件名不一致,额外标注extern "C" __declspec(dllexport)不然不会生成.lib文件
extern "C" __declspec(dllexport) int add(int a, int b) {
return a + b;
}
3. 使用动态链接库
3.1 静态加载动态库
链接步骤
- 将动态库项目生成
MyDll.dll
和MyDll.lib、bing.h拷贝如执行目录
。 - 在主程序项目中,将
MyDll.lib
添加到链接器输入。(右键项目-》属性-》配置属性-》链接器-》输入-》附件依赖项-》添加xxx.Lib)。添加#include "bing.h"引用。
#include <iostream>
#include "bing.h"
int main() {
int result = add(5, 3);
std::cout << "Result: " << result << std::endl;
return 0;
}
3.2 动态加载动态库
使用流程
-
将生成的MyDll.dll拷贝到执行目录下。
-
加载动态库:在运行时,使用系统 API 加载动态库,Windows 使用
LoadLibrary
。 -
获取函数地址:
- 通过
GetProcAddress
(Windows)。 - 将函数地址转换为函数指针进行调用。
- 通过
-
释放动态库:使用
FreeLibrary
(Windows)卸载动态库。
#include <iostream>
#include <Windows.h>
using namespace std;
typedef int (*AddFunction)(int, int); // 定义函数指针类型
int main() {
// 加载动态库
HMODULE hLib = LoadLibrary(TEXT("MyDll.dll"));
if (!hLib) {
cout << "Failed to load MyDll.dll" << endl;
return -1;
}
// 获取 add 函数地址
AddFunction add = (AddFunction)GetProcAddress(hLib, "add");
if (!add) {
cout << "Failed to get add function address" << endl;
FreeLibrary(hLib);
return -1;
}
// 调用函数
int result = add(5, 3);
cout << "Result: " << result << endl;
// 释放动态库
FreeLibrary(hLib);
getchar();
return 0;
}
对比总结
特性 | 静态加载动态库 | 动态加载动态库 |
---|---|---|
加载时机 | 程序启动时 | 程序运行时 |
函数调用方式 | 编译时解析符号,直接调用函数 | 通过函数指针调用 |
依赖性 | 程序启动时需确保 .dll 文件存在 | 运行时可按需加载,无需启动时依赖 |
灵活性 | 较低 | 高 |
性能 | 较高 | 略低,首次加载和解析符号有额外开销 |
适用场景 | 静态加载更适合逻辑固定、对性能要求高的场景; | 动态加载则更适合需要高灵活性、按需加载功能模块的场景。 |