参考:1.带你玩转Visual Studio——带你发布自己的工程库
2.VisualStudio2019 DLL生成并使用教程(C++)最详细Demo教程
什么是程序库?
程序库是写好的,成熟的,可以复用的可执行代码集的二进制形式,可以被操作系统载入内存,被别的程序调用执行。比如STL(Standard Template Library)。
C/C++的程序库有两种:静态库和动态库。将一个程序编译成可执行文件一般经过:预编译–>编译–>链接 这几个过程,而静态库与动态库的区别主要体现在链接这个过程。
静态库:
在链接阶段,会将编译的目标文件.obj 与引用到的库.lib 一起链接打包到可执行文件exe(也称为目标代码)中,程序运行时将不再需要该静态库。
因此最终链接成的可执行文件(.exe)体积较大。在Windows中一般以.lib为后缀名,在Linux中一般以.a为后缀名。
动态库:
也称之为共享库。在链接阶段,动态库.dll并没有真正被连接到目标代码中,只是将这个动态库的声明链接到目标代码中(这样程序运行时才知道怎样使用这个动态库),动态库.dll依然是独立存在的,只有在程序运行时才会将.dll载入到内存中被程序调用。因此程序运行时必须要有这个动态库且放在正确的路径中。
因此最终链接成的可执行文件(.exe)体积较小。在Windows中一般以.dll为后缀名,在Linux中一般以.so为后缀名。
静态库与动态库的区别:
特点 | 静态库 | 动态库 |
对函数库的链接时机 | 在编译的链接阶段完成 | 推迟到程序运行时 |
运行过程与库的关系 | 程序在运行时与静态库再无关系 | 程序在运行时与动态库库需要一直存在且路径正确 |
是否链接到可执行文件 | 静态库被链接合成一个可执行.exe文件 | 动态库不会被链接到可执行文件中 |
目标文件大小 | 体积较大 | 体积较小 |
内存占用度 | 占用内存。如果多个程序使用了同一个静态库,每一个程序者会包含这个静态库 | 节约内存。如果多个程序使用了同一个动态库,可以实现进程之间的资源共享(因此动态库也称为共享库) |
程序移植 | 移植方便 | 移植不太方便,需要所有动态库的头文件 |
程序升级 | 程序升级麻烦,需要下载整个程序进行升级 | 程序升级更简单,只需要升级某个DLL或某个程序,下载一个升级包即可 |
编译出的结果文件 | ProjectName.lib | ProjectName.lib+ProjectName.dll, 这里的ProjectName.lib与静态库的.lib文件不同,这只是一个导入库,只包含了地址符号表等,以便调用方的程序能找到对应的函数,真正的库文件是ProjectName.dll |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
创建工程
实验环境 Visual Studio 2019
创建解决方案
创建一个C++的空项目MainProject,同时生成同名解决方案。
创建并编译静态库
在MainProject解决方案中创建C++空项目StaticLib,用于生成静态库
创建并编译动态库
在MainProject解决方案中创建C++空项目DynamicProject,用于生成动态库
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
静态库
编写静态库代码
StaticLib.h
#pragma once
int StaticLibAdd(int a,int b);
StaticLib.cpp
#include "StaticLib.h"
#include <stdio.h>
int StaticLibAdd(int a, int b) {
printf("StaticLibAdd executed \n");
return a + b;
}
配置工程
编译,查看输出文件目录,其中StaticLib.lib为静态库文件
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
动态库
编写动态库代码
DynamicLib.h
动态库的导出方法前需要加入extern "C" _declspec(dllimport) 来表示要导出的方法
#pragma once
//定义宏
#ifndef IMPORT_DLL
//指的是允许将其给外部调用
#define IMPORT_DLL extern "C" _declspec(dllimport)
#endif
IMPORT_DLL int DynamicLibSub(int a, int b);
DynamicLib.cpp
#include "DynamicLib.h"
#include <stdio.h>
int DynamicLibSub(int a, int b)
{
printf("DynamicLibSub executed \n");
return a - b;
}
配置工程
编译,查看输出文件目录,其中DynamicProject.lib为导入库,DynamicProject.dll为动态库
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
调用静态库
配置MainProject
1.指定头文件(.h)所在路径
2.指定静态库文件(.lib)所在路径
3.指定静态库名称
配置完成,编写调用代码
Main.cpp
#include "StaticLib.h"
#include <stdio.h>
int main() {
int a = 1;
int b = 2;
int addResult = StaticLibAdd(a,b);
printf("%d+%d=%d\n",a,b, addResult);
return 0;
}
运行结果
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
调用动态库
配置MainProject
1.指定头文件(.h)所在路径
2.指定导入库文件(.lib)所在路径
3.指定导入库名称
4.将动态库(.dll)文件放置到可执行文件(.exe)同级目录。找不到dll文件编译会失败
配置完成,编写调用代码
Main.cpp
#include "DynamicLib.h"
#include <stdio.h>
int main() {
int a = 4;
int b = 2;
int subResult = DynamicLibSub(a,b);
printf("%d-%d=%d\n",a,b, subResult);
return 0;
}
运行结果