C++ 动态库和静态库
目的:代码重用
静态库
创建头文件testlib.h
#ifndef TESTLIB_H #define TESTLIB_H // 防止头文件重复包含 // 条件编译指令 // 加减乘除 int add(int a, int b); #endif
创建testlib.cpp
#include "pch.h" #include "framework.h" #include "testlib.h" int add(int a, int b) { return a + b; }
生成解决方案
1>------ 已启动生成: 项目: testlib, 配置: Debug Win32 ------ 1>pch.cpp 1>testlib.cpp 1>testlib.vcxproj -> C:\Users\My\source\repos\testlib\Debug\testlib.lib ========== 生成: 成功 1 个,失败 0 个,最新 0 个,跳过 0 个 ==========
创建新的控制台项目testdll
右键项目,属性,链接器,附加库目录 C:\Users\My\source\repos\testlib\Debug\或相对路径(推荐)
使用lib
#include <iostream> #include "../../testlib/testlib/testlib.h" #pragma comment(lib, "testlib.lib") int main() { printf("请输入两个数字\n"); int a, b; scanf("%d%d", &a, &b); printf("add(a, b)=%d\n", add(a, b)); return 0; }
只需提供头文件和lib文件就可以使用你提供的静态库
动态库
静态库生成的文件全都组合到exe里面
动态库则动态加载,不会嵌入到exe中
vs总文件有好几个G大,但是其exe文件只有几个KB,dll的好处
软件升级,只需要更新动态库重启软件就好了,不需要重新安装新的的编译文件
1.VS2019新建立一个空项目(Project1)
VS有提供dll项目的模板,可是对于我来说反而搞不懂模板中的文档,于是建立空白项目,自己去做简单的配置。
2.解决方案管理器中为项目添加一个头文件,选择新建项
在新建的头文件(testdll.h)中声明要导出的API,添加函数声明
#ifndef TESTDLL_H #define TESTDLL_H int add(int a, int b); int sub(int a, int b); #endif // !TESTDLL_H
3.添加一个源文件,实现申明的API函数
#include "testdll.h" int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; }
4.修改项目->项目属性->常规->配置类型为动态库(.DLL)
生成解决方案
1>------ 已启动生成: 项目: testdll, 配置: Debug x64 ------ 1>testdll.cpp 1>testdll.vcxproj -> C:\Users\My\source\repos\Project1\Debug\Prodect1.dll ========== 生成: 成功 1 个,失败 0 个,最新 0 个,跳过 0 个 ==========
将dll文件拖到dependency walker中
需要添加,声明导出函数
#pragma once #ifndef TESTDLL_H #define TESTDLL_H __declspec(dllexport) int add(int a, int b); __declspec(dllexport) int sub(int a, int b); #endif // !TESTDLL_H
重新生成
使用动态库有两种方式
隐式调用动态库
在project1项目中添加预定义
修改 testdll.h
#ifndef TESTDLL_H #define TESTDLL_H #ifdef _DLLAPI #define DLLAPI __declspec(dllexport) #else #define DLLAPI __declspec(dllimport) #endif // !DLLAPI int DLLAPI add(int a, int b); int DLLAPI sub(int a, int b); #endif // !TESTDLL_H
如果DLLAPI定义了,则DLLAPI是__declspec(dllexport) ,因为刚刚预定义了所以是__declspec(dllexport) 。但在testd项目中我们没有预定义因此是__declspec(dllimport) 。
添加项目testdll
右键项目,属性,C/C++,常规,附加包含目录
否则无法导入头文件
#include <iostream>
#include "./testdll.h"
#pragma comment(lib, "Project1.lib")
int main()
{
printf("请输入两个数字\n");
int a, b;
scanf("%d%d", &a, &b);
printf("add(a, b)=%d\n", add(a, b));
return 0;
}
右键项目,属性,链接器,附加库目录,C:\Users\My\source\repos\Project1\Debug
SDL检查 否
运行
显示调用动态库
修改testdll.cpp
#include <iostream> #include "./testdll.h" //#pragma comment(lib, "Project1.lib") #include <Windows.h> // 定义函数指针类型 typedef int (*PADD)(int a, int b); int main() { printf("请输入两个数字\n"); int a, b; scanf("%d%d", &a, &b); // 加载dll文件 HMODULE hDLL = LoadLibrary(L"C:\\Users\\My\\source\\repos\\Project1\\Debug\\Project1.dll"); if (hDLL == NULL) { printf("加载失败\n"); return 0; } PADD padd = (PADD)GetProcAddress(hDLL, "add"); printf("add(a, b)=%d\n", padd(a, b));
FreeLibrary(hDLL);
return 0; }
运行程序,会报异常,找不到add函数
查看dependency walker
复制函数名,修改上面程序
PADD padd = (PADD)GetProcAddress(hDLL, "?add@@YAHHH@Z");
运行正常
C语言可以直接使用add,但C++不行
因此,我们要导入C语言的配置
修改testdll.h
#ifdef _DLLAPI #define DLLAPI __declspec(dllexport) #else #define DLLAPI __declspec(dllimport) #endif // !DLLAPI extern "C" DLLAPI int add(int a, int b); extern "C" DLLAPI int sub(int a, int b); #endif // !TESTDLL_H
重新生成Project1
函数改为add,可正常运行testdll
为了这个改名,微软还提供了模块定义文件
头文件testdll.h
#pragma once #ifndef TESTDLL_H #define TESTDLL_H int add(int a, int b); int sub(int a, int b); #endif // !TESTDLL_H
添加新建项,代码,模块定义文
LIBRARY Project1
EXPORTS
add
sub
重新生成
运行testdll