Windows下动态链接库和静态链接库的生成以及调用
一、简介
为了提高代码的复用性,引入了库,库是一段可执行代码的二进制形式,可以被操作系统直接载入内存使用。一般分为动态库和静态库,在Windows操作系统中静态库是以 .lib 为后缀的文件,动态库是以 .dll 为后缀的文件。
C++程序编译以及调用库的过程如下:
可以看到库是在链接过程和目标文件一起打包最终生成可执行文件,另外可以看到静态库和动态库是编译型语言所特有的,对于非编译型语言例如python,在实现上有所不同。
以下是静态链接库和动态链接库的区别:
1. 静态链接库(.lib):在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中,相当于在可执行文件中每个用到库的地方,都会插入一份库的代码,这样会增加最终生成的可执行文件的体积。
2. 动态链接库(.dll):在链接阶段,动态库并不会被插入到目标文件.o中,而是在.exe可执行文件运行时才会被加载到内存,然后被程序调用,这样能大大减小生成的可执行文件的体积,并且动态链接库被修改时,并不需要重新编译生成源代码。
二、生成静态链接库(.lib)和动态链接库(.dll)
- 首先使用vs2019新建空项目,命名选择存储位置。
- 在项目中新建空白 .h 头文件和 .cpp 源文件,如下:
- .h 头文件输入以下代码:
1 | // addnum.h |
- .cpp 源文件输入以下代码:
1 | // addnum.cpp |
- 其中.h 头文件中extern “C” 表示使用C语言方式生成链接库,而_declspec(dllexport)用于声明库函数,.cpp源文件是该函数的具体实现过程,AddTwoInt()函数的功能是计算两个整形数之和。
-
点击项目->属性->常规->配置类型,设置当前项目的生成类型。如下图:
可以看到,这里可以选择生成的类型,如果要生成静态链接库,选择静态库,如果要生成动态链接库,选择动态库,选择之后点击确定即可。 -
点击生成,生成解决方案,然后就会在相应文件夹下生成库文件,如下:
- 生成静态库(.lib)
- 生成动态库(.dll)
生成了对应的动态库和静态库之后,下面就可以编写源程序来调用库。
三、静态链接库的调用
相较于动态链接库,静态链接库的调用相对简单,我们只需要在调用函数中声明好静态库中的函数接口,即可完成调用。
- 首先还是使用vs2019新建一个空项目,然后在项目下新建 addnum.h 和 main.cpp 文件,其中addnum.h 文件是对库的函数接口的说明,main.cpp 调用库函数。代码分别为:
- addnum.h文件:
1 | // addnum.h |
- main.cpp文件:
1 | // main.cpp |
- addnum.h文件主要声明AddTwoInt()函数是从外部库导入的,main()函数调用AddTwoInt()函数计算"7+19"的结果。
- 将之前生成的libtest.lib静态链接库添加到项目的资源文件,完成后如下:
- 按Ctrl+F5或者点击调试->开始执行,运行源代码,得到结果如下:
可以看到程序返回结果为26,说明调用成功。
四、动态链接库的调用
动态链接库的两种调用方式
相对于调用静态库,调用动态库的过程更加复杂。主要由两种方法:
- 第一种方法是仅使用之前编译生成的.dll动态链接库文件,程序在运行时将库直接加载到内存中,获取函数的入口地址,然后利用函数指针直接调用。
- 第二种方法是使用编译动态库过程中产生的静态库,这个静态库是系统自动生成的,其内部并不包含函数接口,作用只是获得动态库的函数地址,使得可以像调用静态库一样调用动态库。
仅使用.dll文件
- 同样的,首先新建一个空项目,在项目中新建一个.cpp源文件以及将之前生成的.dll动态库文件添加到项目文件夹下以及项目中,如下:
- main.cpp中的代码:
1 | // main.cpp |
- 运行,得到结果如下:
使用.h+.dll+.lib文件
这种方法调用需要使用编译生成动态链接库时自动生成的静态库,调用方法类似调用静态库,但是本质上却是使用的动态库。
- 同样的,首先新建一个空项目,在项目下添加addnum.h和main.cpp文件,然后将生成的动态库和静态库都复制到项目文件夹下,以及添加到项目,如下:
- 由于这里调用动态库的方法和调用静态库一样,因此此处addnum.h和main.cpp的内容页数一样的,如下:
- addnum.h文件:
1 | // addnum.h |
- main.cpp文件:
1 | // main.cpp |
- 运行,结果如下:
也成功的得到了结果。