博客主页:何曾参静谧的博客
文章专栏:「C/C++」C/C++学习
目录
- 相关术语
- 案例环境:Win10+VS2019
- 一、链接库介绍
- 二、静态链接库(Static Library)
- 2.1、静态库优缺点
- 2.2、静态库的创建
- 2.2.1、创建静态库项目
- 2.2.2、添加.h头文件和.cpp文件
- 2.2.3、编译生成.lib文件
- 2.3、静态库的使用
- 三、动态链接库(Dynamic Linking Library)
- 3.1、动态库优缺点
- 3.2、动态库的创建
- 3.2.1、创建动态库项目
- 3.2.2、添加dllsum.h头文件和dllsum.cpp文件
- 3.2.3、编译生成dllsum.lib与dllsum.dll文件
- 3.3、动态库*.dll使用
- 3.3.1方法一:直接使用
- 3.3.2方法二:使用LoadLibrary()
相关术语
静态链接库(Static Linking Library):
是在编译时将库代码与应用程序静态链接在一起的库。它们被编译为二进制文件,并在运行时作为应用程序的一部分被载入内存。这种库被称为“静态”是因为它们在编译时被链接,这意味着它们的代码与应用程序的其余部分被编译为单个二进制文件。文件后缀:.lib
,.a
。
动态链接库(Dynamic Linking Library):
是在应用程序运行时才被加载到内存中的库。它们不会被编译为二进制文件,而是被存储为单独的文件。这些库共享代码,并被多个应用程序使用,以提高效率和避免代码冗余。文件后缀:.dll
,.so
。
案例环境:Win10+VS2019
代码的分发方式:
源码方式
:头文件
+源文件
动态库方式
:头文件
+lib文件
+dll文件
静态库方式
:头文件
+lib文件
一、链接库介绍
链接库(library)
是一种常见的软件开发概念,指的是包含可重用代码的二进制文件(通常是动态链接库)。在运行时,程序可以将某个库链接到自己的代码中,从而使用该库中的函数和其他代码。链接库的使用可以提高代码的复用性、减少程序体积、加快编译速度等。
平台集 | 静态库 | 动态库 |
---|---|---|
Windows | .lib文件 | .dll文件 |
Linux | .a文件 | .so文件 |
Mac OS | .a文件 | .dylib文件 |
C语言和C++的常用的CRT,后面红色的d代表多线程,p代表C++
C语言 | C++ | |
---|---|---|
静态库 | libc.lib 或 libcd.lib libcmt.lib 或 libcmtd.lib | LIBCP.LIB 或 LIBCPD.LIB LIBCPMT.LIB 或 LIBCPMTD.LIB |
动态库 | msvcrt.dll 或 msvcrtd.dll | MSVCPRT.DLL 或 MSVCPRTD.DLL |
二、静态链接库(Static Library)
静态链接库(Static Linking Library):
是在编译时将库代码与应用程序静态链接在一起的库。它们被编译为二进制文件,并在运行时作为应用程序的一部分被载入内存。这种库被称为“静态”是因为它们在编译时被链接,这意味着它们的代码与应用程序的其余部分被编译为单个二进制文件。文件后缀:.lib
,.a
。
2.1、静态库优缺点
静态链接库的优点:
- 一劳永逸:在程序编译时,所有需要的库的代码都被打包成一个可执行文件。这样一来,在将程序运行到其他机器上时,您不必再携带各种动态库而是只需一份可执行文件就好了。
- 执行速度更快:因为所有代码都在一个文件中,所以不需要运行时加载,执行速度很快。
- 不会出现库版本冲突问题
静态链接库的缺点:
占用空间较大
,相同功能的多个程序都要各自有一份库文件- 更新麻烦,每次修改库文件都需要
重新编译与分发
2.2、静态库的创建
2.2.1、创建静态库项目
2.2.2、添加.h头文件和.cpp文件
以一个简单求和函数为案例,创建两个文件
libsum.h
,libsum.cpp
。
libsum.h文件
#pragma once
int sum(int a, int b);
libsum.cpp文件
#include "libsum.h"
int sum(int a, int b){
return a + b;
}
2.2.3、编译生成.lib文件
2.3、静态库的使用
- 包含头文件的libsum.h头文件
#include"libsum.h"
- 包含libsum.lib文件两种方法:
– 方法一:文件中添加#pragma comment(lib,"libsum.lib")
– 方法二:右键项目->属性->配置属性->链接器->输入->附加依赖项->libsum.lib
main.cpp
#include"libsum.h"
#include <iostream>
#pragma comment(lib,"libsum.lib")
int main(){
cout << sum(11,22) << endls;
return 0;
}
三、动态链接库(Dynamic Linking Library)
动态链接库(Dynamic Linking Library):
是在应用程序运行时才被加载到内存中的库。它们不会被编译为二进制文件,而是被存储为单独的文件。这些库共享代码,并被多个应用程序使用,以提高效率和避免代码冗余。文件后缀:.lib
,.so
。
3.1、动态库优缺点
动态链接库的优点:
节约内存和代码重用:
当应用程序使用动态链接时,多个应用程序可以共享磁盘上单个DLL副本。便于更新和维护:
只需替换动态链接库,程序就能获取新的功能。可扩展性:
DLL文件与EXE文件独立,只要接口不变,升级程序只需要更新DLL文件不需要重新编译应用程序。复用性:
DLL的编译与具体的编译语言及编译器无关,不同语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数。
动态链接库的缺点:
DLL HELL(DLL地狱):
在增加成员变量、修改导出类的基类等操作可能导致意想不到的后果。- 需要载入时才能使用,/runtime,例如QTGUI库
- 多进程间的共享使用需要考虑锁的问题,
- 存在库版本冲突问题
3.2、动态库的创建
3.2.1、创建动态库项目
3.2.2、添加dllsum.h头文件和dllsum.cpp文件
以一个简单求和函数为案例,创建两个文件
dllsum.h
,dllsum.cpp
。
需要使用到_declspec(dllexport)
进行函数导出,extern"C"
为强制使用C语言语法(无法函数重载)。
dllsum.h文件
#pragma once
extern"C" _declspec(dllexport) int sum(int a, int b);
dllsum.cpp文件
#include "dllsum.h"
int sum(int a, int b){
return a + b;
}
3.2.3、编译生成dllsum.lib与dllsum.dll文件
PS:此处的.lib文件不是静态库文件而是dll的符号文件。
3.3、动态库*.dll使用
3.3.1方法一:直接使用
- 包含头文件的头文件
#include "dllsum.h"
- 包含
dllsum.lib
文件两种方法:
– 方法一:文件中添加#pragma comment(lib,"dllsum.lib")
– 方法二:右键项目->属性->配置属性->链接器->输入->附加依赖项->dllsum.lib
- 🎈使用时文件中需要包含
dllsum.dll
文件
main.cpp
#include "dllsum.h"
#include <iostream>
#using namespace std;
#pragma comment(lib,"dllsum.lib")
extern "C" _declspec(dllimport) int sum(int a, int b);
int main(){
cout << sum(11,22) << endl;
return 0;
}
3.3.2方法二:使用LoadLibrary()
- 加载动态库:
LoadLibrary()
HMODULE WINAPI LoadLibrary( _In_LPCWSTR lpLibFileName, //动态链接库的名称 );//返回值:调用成功,返回库模块的句柄。调用失败返回0。
- 获取函数地址:
GetProcAddress()
FARPROC WINAPI GetProcAddress( HMODULE hModule, //模块的句柄 LPCSTR lpProcName //函数名 或 WORD叙数值 );//返回值:调用成功,输出函数地址。调用失败返回NULL。
- 释放动态库:
FreeLibrary()
BOOL WINAPI FreeLibrary( _In_HMODULE hLibModule //模块的句柄 );
- 获取错误信息:
GetLastError()
main.cpp
#include <iostream>
#include <windows.h>
#using namespace std;
int main(){
//1.加载dll
HMODULE h = LoadLibrary("dllsum.dll");
//2.获取函数地址
typedef int(*PDLLSUM)(int,int);
//3.利用函数指针调用函数
if(1)
PDLLSUM pdllsum = (PDLLSUM)GetProcAddress(h,"sum");//通过函数名调用
else
PDLLSUM pdllsum = (PDLLSUM)GetProcAddress(h,(char*)1);//通过序号调用
cout << pdllsum(11,22) << endl;
//4.释放dll
FreeLibrary(h);
return 0;
}