文章目录
- 一、静态连接与动态连接
- 二、 动态链接库(DLL)的创建
- 三、dll库的使用
- 四、 动态链接链接库工作原理
- 五、extern "C"
一、静态连接与动态连接
静态库和动态库区别是库的加载时间不同。静态库:在链接阶段库将会与.o目标文件一起打包生成可执行文件,成为可执行文件的一部分,后续此库就可以消失了。也就是说在编译的最后一步(链接阶段),如果程序需要使用静态库,在这一步都会一起打包到可执行文件中。
优点:
- 使可执行文件依赖项少,已经被打包到可执行文件中了
- 编译阶段完成链接,执行期间代码装载速度快
缺点:
- 使可执行文件变大
- 若作为其他库的依赖库,将会造成多余的副本,因为必须与目标文件打包
- 升级不方便,升级必须重新编译
动态库:在编译阶段都不会有任何动作,只有在程序运行时才被加载,也就是动态库的链接是发生在程序运行时期的,它和可执行文件是分开的,只是可执行文件在运行的某个时期调用了它。
优点:
-
动态库可以实现进程之间资源共享,有一份就行。
-
升级程序简单,不需要重新编译。
缺点:
-
运行期间在加载,将会减慢代码执行速度。
-
增加程序的依赖项,必须跟着可执行文件一起。
二、 动态链接库(DLL)的创建
- VS2019新建动态连接库项目
可以看到新建的项目中自带framework.h, pch.h, dllmain.cpp, pch.cpp四个文件,这是需要新建自己的.h和.cpp文件。 - 分别创建用于声明和定义函数的头文件dlltest.h和源文件dlltest.cpp
然后点击生成,编译器报错“……不是有效的win32程序“。
然后打开debug或者release文件夹,可以看到有.lib 和.dll文件。
三、dll库的使用
加载动态库有两种方式,分为隐式加载和显示加载:
隐式加载:所需文件:接口.h头文件,dll文件,lib文件。.h和.lib加载方式与静态加载完全一致。但.dll文件必须放在环境变量指定的目下。当然通常是与目标.exe文件放在一起。
显式加载:所需文件:dll文件。利用LoadLibrary()函数进行加载。
下面介绍一下常用的隐式加载的方法:
(1) 需要将创建的.dll文件以及.lib文件还有定义的.h头文件,拷贝至我们需要测试的新项目的目录下。
(2)将拷贝的头文件添加到空白项目中.
(3)在属性—链接器—输入—附加依赖项中添加我们拷贝过来的.lib文件。
(4)创建一个.cpp源文件开始进行动态库的调用,包含头文件,并且删掉头文件中的#include “pch.h”,随后直接可以调用封装的函数。
四、 动态链接链接库工作原理
- __declspec是Microsoft VC中专用的关键字,它配合着一些属性可以对标准C/C++进行扩充。__declspec关键字出现在声明的前面。
- __declspec(dllexport)声明导出函数、类、对象等供外部调用,省略.def文件(.def文件(模块定义文件)是包含一个或多个描述各种DLL属性的Module语句的文本文件,如果不提供__declspec(dllexport)导出DLL函数,则DLL需要提供.def文件)。
- __declspec(dllimport)用于Windows中,从别的动态库中声明导入函数、类、对象等供本动态库或exe文件使用。当使用DLL中的函数时,不需要显示地导入函数,编译器也可自动完成导入。__declspec(dllimport)可以确定函数是否存在于DLL中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨DLL边界的函数调用中。
五、extern “C”
void Swap(int a, int b);
C编译后,函数名变为 _Swap
C++编译后,因为有重载语法的原因,函数名变为 _Swap_int_int
同一个函数经过C和C++编译后,函数名不同。extern “C” 让C++以C的命名风格编译代码。