一、静态库和动态库
1、库的定义
库,就是代码重用,写过的代码封装好了,可以直接调用。其中,二进制格式的文件,有静态库(.lib)和动态库(.dIl)之分。这两种库都不能独立运行,必须加载到exe可执行文件中,
2、区别
静态库:
- 优点:不需要外部库的支持
- 缺点:静态库编译的程序体积比较大(lib + obj => exe),不便于升级,需要程序整体重新编译生成,不能后台默默升级
动态库:
- 优点:在编译的时候,不会将dll编译到exe里面,体积比较小,在需要的时候动态加载dll到内存里面,不要的时候,可以卸载,可以便于升级,便于模块的升级,只要替换某个dll就可以,不需要整体替换。
- 缺点:需要dll的支持,如果缺少dll,会报错,程序启动不了
二、静态库创建和使用
1、生成静态库
- 打开VS,创建静态库工程。
静态库
-
以简单的加减法为例,创建
.cpp
和.h
文件test.cpp
:
#include "testlib.h" //加法运算 int add(int a, int b) { return a + b; } //减法运算 int sub(int a, int b) { return a - b; }
testlib.h
:
#ifndef _TESTLIB_H #define _TESTLIB_H //加法运算 int add(int a, int b); //减法运算 int sub(int a, int b); #endif
- release 产生 lib 文件,此处在属性中关闭预编译头。打开 release 文件夹,就可以看见 lib 文件。
- 将库整理好,以供调用。创建 testlib 文件夹,内新建三个文件夹,分别为bin(放置.dll文件)、include(放置.h文件)、lib(放置lib文件)
2、调用静态库
- 创建新项目,控制台应用的新工程,添加cpp文件。
控制台
-
在该控制台工程路径下,复制上述的 testlib 文件夹(工程路径就是工程右击文件资源管理器)
-
打开工程属性
属性-
C/C++
—常规
—附加包含目录
,添加路径。此处添加 testlib 文件夹的 include 文件夹。
可以是绝对路径也可以是相对路径。
绝对路径,例如 :C:\Windows\SystemResources\Microsoft.Windows.SecHealthUI
不方便移植
相对路径:相对于”当前工程所在文件夹“的位置
.
表示当前目录
..
表示上一级目录
/
表示根目录
../../
上上级
../../../
上上上级
../../../../
上上上上级
例如 :./testlib/include
-
链接器
—常规
—附加库目录
, 添加目录。此处添加testlib 文件夹的 lib 文件夹。
即,./testlib/lib
-
链接器
—输入
—附加依赖项
, 添加目录。此处添加调用的 .lib文件的文件名
即testlib.lib
- 如果这里不添加 lib。也可以在 cpp 文件手动添加,在开头
#pragma comment(lib,"testlib.lib")
- 如果这里不添加 lib。也可以在 cpp 文件手动添加,在开头
-
-
在cpp文件开头,添加
#include
导入的testlib.h
文件 ,就可以调用库内相应函数功能,即#include "testlib.h"
-
编写代码
#include <stdio.h> #include <testlib.h> int main() { int a = 10; int b = 20; int c = sub(a, b); int d = add(a, b); printf("c=%d\n", c); printf("d=%d\n", d); return 0; }
-
运行,就可以实现调用的静态库的加减法函数的功能。结果为
c=-10
,d=30
。
3、其他
- 重新生成lib后,将库文件重新覆盖到控制台工程目录里(替换原来的 文件)
- c++支持函数重载;c语言不行(注:在函数前加上
extern "C"
可以以C语言编译)
三、动态库的生成和调用
1、生成动态库
-
打开VS,创建新项目—— 动态链接库项目
-
新建.cpp文件 .h文件 。以简单的加减法为例。
test.cpp
:#include "testdll.h" //加法 int add(int a, int b) { return a + b; } //减法 int sub(int a, int b) { return a - b; }
testdll.h
:#ifndef _TESTDLL_H #define _TESTDLL_H __declspec(dllexport) int add(int a, int b); __declspec(dllexport) int sub(int a, int b); #endif
- 加上
__declspec(dllexport)
,表示该dll导出使用。不加表示,该函数仅提供内部接口,供内部使用。__declspec(dllexport)
——导出符号,以c++方式导出函数的接口,编译器会将函数名修改;C语言方式编译则不会。
- 加上
-
(关闭预编译头 )release 产生 .dll文件 以及 .lib和.exp文件
- 动态库中产生的lib的文件,不是真正的静态库文件,其中不包含执行代码,执行代码在dll文件中。lib文件仅仅只是包含导出信息。
-
创建第三方库文件夹 testdll。将工程产生的dll复制进bin文件夹 , 将.h文件复制进 include文件夹,将.lib文件复制进 lib文件夹。
2、调用动态库
- 打开VS,创建控制台项目demo,把上述导出的第三方库文件夹 testdll 复制到 demo工程路径。
- 项目属性
- C/C++ —— 常规 —— 附加包含目录:此处应该添加 自定义库的include文件夹路径
./testdll/include
- 链接器 —— 常规 —— 附加库目录 :此处添加 自定义库的lib文件夹路径
./testdll/lib
- 链接器 —— 输入 —— 附加依赖项 :此处添加lib文件的文件名
testlib.lib
- C/C++ —— 常规 —— 附加包含目录:此处应该添加 自定义库的include文件夹路径
- 在demo 项目添加 cpp 文件
#include <stdio.h> #include <testdll.h> int main() { int a = 10; int b = 20; int c = add(a, b); printf("a=%d\n", c); return 0; }
- 若此时运行,会发现错误,提示没有依赖的 dll
没有依赖的 dll
- 此时将dll文件移动到.exe文件的文件夹中。再次运行,即可正常实现功能。
- 单独创建文件夹,只放进去exe和dll文件,双击exe就可以正常运行,不用打开VS。
3、关于dll导出的其他方法
-
导出方式1:
可以在头文件,做一个宏定义替换导出符号.h:
#ifndef _TESTDLL_H #define _TESTDLL_H #ifndef _DLLAPI #define DLLAPI __declspec(dllimport) #else #define DLLAPI __declspec(dllexport) #endif DLLAPI int add(int a, int b); DLLAPI int sub(int a, int b); #endif
-
导出方式2:
在dll开发项目工程里,添加新建项.def文件LIBRARY testdll EXPORTS add sub