十二、C++速通秘籍—静态库,动态库
上一章节:
十一、C++速通秘籍—多线程-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/147055932?spm=1001.2014.3001.5502
本章节代码:
cpp2/library · CuiQingCheng/cppstudy - 码云 - 开源中国https://gitee.com/cuiqingcheng/cppstudy/tree/master/cpp2/library
目录
上一章节:
本章节代码:
一、编程后为什么会引入“库”,什么是库?
二、库分为哪几类? - 静态库,动态库
1、静态库(.a 或.lib)
2、动态库(.so 或.dll)
三、Linux/windows系统下的库
1、Linux 下表现形式
2、Windows 下表现形式
四、Linux/Windows下使用静态库,什么场景下使用静态库?
1、适用场景
2、Linux 下创建和使用静态库
2.1、创建静态库
2.2、使用静态库
3、Windows 下创建和使用静态库
3.1、创建静态库
3.2、使用静态库
五、Linux/Windows下使用动态库,什么场景下使用动态库?
1、适用场景
2、Linux 下创建和使用动态库
2.1、创建动态库
2.1、使用动态库
3、Windows 下创建和使用动态库
3.1、创建动态库
六、静态库,与动态库二者的区别
内存占用
部署难度
运行效率
可维护性
七、总结
一、编程后为什么会引入“库”,什么是库?
想象一下你是一位超级大厨,每次做饭都要从头开始种粮食、养牲畜、采摘蔬菜,那得花费多少时间和精力呀!在编程的世界里也是如此,如果每次编写程序都要从头开始实现一些常用的功能,比如文件读写、数学计算等,那程序员可就太累啦。于是,“库”就应运而生了。
库就像是一个装满各种工具的百宝箱,里面存放着已经编写好的代码,这些代码实现了各种各样的功能。当程序员需要使用某个功能时,不需要自己重新编写代码,只需要从这个百宝箱里拿出对应的工具(也就是调用库中的代码)就可以了。比如说,在 C++ 中,我们之前已经接触过std标准库,就提供了很多常用的功能,像字符串处理、容器管理等。你只需要包含相应的头文件,就可以使用这些功能,就像大厨从厨房里拿出现成的调料一样方便。
二、库分为哪几类? - 静态库,动态库
库主要分为两类:静态库和动态库,它们就像是两种不同类型的百宝箱。
1、静态库(.a 或.lib)
静态库就像是一个可以被复制的百宝箱。当你使用静态库时,编译器会把静态库中的代码完整地复制到你的可执行文件中。这就好比你把百宝箱里的工具都拿出来,放进自己的口袋里,以后无论走到哪里,都可以随时使用这些工具,不需要再依赖原来的百宝箱。
2、动态库(.so 或.dll)
动态库则像是一个共享的百宝箱,存放在一个公共的地方。当你的程序需要使用动态库中的代码时,程序会在运行时去这个公共的地方查找并加载所需的代码。这就好比你需要某个工具时,不需要把整个百宝箱都拿走,只需要去公共的地方借用一下工具,用完后再还回去。
三、Linux/windows系统下的库
1、Linux 下表现形式
在 Linux 系统中,静态库的文件扩展名通常是 `.a`,例如 `libexample.a`;动态库的文件扩展名通常是 `.so`,例如 `libexample.so`。这些库文件一般存放在 `/usr/lib` 或 `/usr/local/lib` 等目录下。
2、Windows 下表现形式
在 Windows 系统中,静态库的文件扩展名是 `.lib`,例如 `example.lib`;动态库的文件扩展名是 `.dll`,例如 `example.dll`。这些库文件通常存放在系统目录(如 `C:\Windows\System32`)或程序的安装目录下。
下面是一个简单的对比图:
系统 | 静态库扩展名 | 动态库扩展名 |
Linux | .a | .so |
Windows | .lib | .dll |
四、Linux/Windows下使用静态库,什么场景下使用静态库?
1、适用场景
当你需要将程序打包成一个独立的可执行文件,并且不希望依赖外部的库文件时,就可以使用静态库。比如你开发了一个小型的游戏,希望用户下载后可以直接运行,不需要额外安装其他库,这时就可以使用静态库。
2、Linux 下创建和使用静态库
2.1、创建静态库
假设我们有一个简单的 C++ 函数 `add`,用于计算两个整数的和,代码如下:
add.cpp
int add(int a, int b)
{return a + b;
}
首先,将 `add.cpp` 编译成目标文件:(add.o)
g++ -c add.cpp -o add.o
然后,使用 `ar` 工具将目标文件打包成静态库:
ar rcs libadd.a add.o
这样,我们就创建了一个名为 `libadd.a` 的静态库。
2.2、使用静态库
现在,我们来编写一个主程序 `main.cpp` 来使用这个静态库:
main.cpp
#include <iostream>// 声明 add 函数
extern int add(int a, int b);int main() {int result = add(3, 5);std::cout << "3 + 5 = " << result << std::endl;return 0;
}
编译并链接静态库:
g++ main.cpp -L. -ladd -o main
其中,`-L.` 表示在当前目录下查找库文件,`-ladd` 表示链接名为 `libadd.a` 的静态库。最后,运行可执行文件:
./main
3、Windows 下创建和使用静态库
3.1、创建静态库
同样使用上面的 `add.cpp` 代码,打开 VisualCode,创建一个 `add.cpp`文件。
代码:
int addWin(int a, int b)
{return a + b;
}
这里编译生成.lib,这里需要修改VsCode,中的tasks.json;
通过这个文件创建了两个编译任务:create_targe_file/create_static_lib
{"tasks": [{ // 生成目标文件"type": "shell","label": "create_target_file","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\g++.exe","args": ["-fdiagnostics-color=always","-c","${file}","-o","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.o"],"options": {"cwd": "${fileDirname}"},"problemMatcher": ["$gcc"],"group": {"kind": "build","isDefault": true}},{ // 生成静态库"label": "create_static_lib","type": "shell","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\ar.exe","args": ["rcs","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.lib","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.o"],"group": {"kind": "build","isDefault": true},"presentation": {"reveal": "always"},"problemMatcher": "$gcc"}],"version": "2.0.0"
}
(1)、打开命令面板(Ctrl+Shift+P)
(2)、输入 Tasks: Run Task 并选择 create_target_file
(3)、创建静态库,跟步骤2相同选择create_static_lib
3.2、使用静态库
创建一个staticEx.cpp
// 链接静态库
#include <iostream>// 声明 addWin 函数
extern "C" int addWin(int a, int b);int main() {int result = addWin(5, 5);std::cout << "5 + 5 = " << result << std::endl;return 0;
}
配置tasks.json:
{"tasks": [{ // 生成目标文件"type": "shell","label": "create_target_file","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\g++.exe","args": ["-fdiagnostics-color=always","-c","${file}","-o","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.o"],"options": {"cwd": "${fileDirname}"},"problemMatcher": ["$gcc"],"group": {"kind": "build","isDefault": true}},{ // 生成静态库"label": "create_static_lib","type": "shell","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\ar.exe","args": ["rcs","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.lib","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.o"],"group": {"kind": "build","isDefault": true},"presentation": {"reveal": "always"},"problemMatcher": "$gcc"},{ // 生成可执行文件"label": "create_exe_file","type": "shell","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\g++.exe","args": ["-fdiagnostics-color=always","-c", // 编译参数"${file}","-L${fileDirname}\\..\\..\\build","-o","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.exe","-static"],"group": {"kind": "build","isDefault": true},"presentation": {"reveal": "always"},"problemMatcher": "$gcc"}],"version": "2.0.0"
}
五、Linux/Windows下使用动态库,什么场景下使用动态库?
1、适用场景
当多个程序需要共享相同的代码,或者库文件需要经常更新时,使用动态库就非常合适。比如操作系统中的一些公共库,多个程序都可以使用这些库中的功能,这样可以节省系统资源。
2、Linux 下创建和使用动态库
2.1、创建动态库
还是使用上面的 `add.cpp` 代码,将其编译成动态库:
g++ -fPIC -c add.cpp -o add.o
g++ -shared -o libadd.so add.o
其中,`-fPIC` 选项用于生成位置无关代码,`-shared` 选项用于创建动态库。
2.1、使用动态库
编写主程序 `main.cpp`:
// main.cpp
#include <iostream>// 声明 add 函数
extern int add(int a, int b);int main() {int result = add(9, 8);std::cout << "9 + 8 = " << result << std::endl;return 0;
}
编译并链接动态库:
g++ main.cpp -L. -ladd -o mainso
运行程序前,需要设置动态库的搜索路径:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
./main
3、Windows 下创建和使用动态库
3.1、创建动态库
在 VsCode 中创建两个文件`dyAdd.h/dyAdd.cpp`, 在dyAdd.h中添加一个导出函数的声明,dyAdd.cpp中实现函数功能:
dyAdd.h
// 动态库
#ifndef _DYADD_H_
#define _DYADD_H_#ifdef DYADD_DLL_EXPORTS
#define DYADD_API __declspec(dllimport)
#else
#define DYADD_API __declspec(dllexport) // 导出
#endifextern "C" DYADD_API int add(int a, int b);#endif
dyAdd.cpp
#include "dyAdd.h"extern "C" DYADD_API int add(int a, int b)
{return a + b;
}
tasks.json
{"tasks": [{ // 生成目标文件"type": "shell","label": "create_target_file","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\g++.exe","args": ["-fdiagnostics-color=always","-c","${file}","-o","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.o","-DDYADD_EXPORTS" // 添加此行以定义 DYADD_EXPORTS 宏],"options": {"cwd": "${fileDirname}"},"problemMatcher": ["$gcc"],"group": {"kind": "build","isDefault": true}},{ // 生成动态库"label": "create_dynamic_lib","type": "shell","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\g++.exe","args": ["-fdiagnostics-color=always","-g","-shared","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.o","-o","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.dll"],"group": {"kind": "build","isDefault": true},"presentation": {"reveal": "always"},"problemMatcher": "$gcc"},{ // 通过动态库生成可执行文件"label": "create_exe_dyfile","type": "shell","command": "C:\\Qt\\Qt5.12.8\\Tools\\mingw730_64\\bin\\g++.exe","args": ["-fdiagnostics-color=always","-g","${file}","-I${fileDirname}","-L${fileDirname}\\..\\..\\build","-o","${fileDirname}\\..\\..\\build\\${fileBasenameNoExtension}.exe","-ladd"],"group": {"kind": "build","isDefault": true},"presentation": {"reveal": "always"},"problemMatcher": "$gcc"}],"version": "2.0.0"
}
这里第一步,第二步,执行后生成了dyAdd.dll,以及编译的中间文件dyAll.o,编译方法都是通过控制面板按步骤生成:
使用动态库
dynamicEx.cpp
#include <iostream>
#include <windows.h>// 动态加载
typedef int (*AddFunction)(int, int);int main() {HINSTANCE hDLL = LoadLibrary("dyAdd.dll");if (hDLL != NULL) {AddFunction add = (AddFunction)GetProcAddress(hDLL, "add");if (add != NULL) {int result = add(3, 5);std::cout << "3 + 5 = " << result << std::endl;}else {std::cout << "Failed to get add function address." << std::endl;}FreeLibrary(hDLL);}return 0;
}
编译并运行程序
六、静态库,与动态库二者的区别
内存占用
静态库会将代码复制到可执行文件中,导致可执行文件体积较大,占用更多的磁盘空间;而动态库在多个程序间共享,只需要在内存中加载一份,节省了磁盘空间和内存资源。
部署难度
静态库部署简单,可执行文件不依赖外部库文件,用户只需要运行可执行文件即可;动态库部署时需要确保库文件存在于系统的指定路径中,否则程序可能无法正常运行。
运行效率
静态库的代码在编译时就已经链接到可执行文件中,运行时无需额外加载,效率相对较高;动态库在运行时需要加载,会有一定的性能开销。
可维护性
如果库文件需要更新,使用静态库的程序需要重新编译;而使用动态库的程序只需要替换库文件即可,不需要重新编译。
下面是一个对比表格:
比较项 | 静态库 | 动态库 |
内存占用 | 大 | 小 |
部署难度 | 简单 | 复杂 |
运行效率 | 高 | 低 |
可维护性 | 低 | 高 |
七、总结
掌握静态库和动态库的使用,能让你的 C++ 编程之路更加顺畅,就像大厨拥有了得心应手的工具,做出更加美味的菜肴一样!希望通过这篇博客,你能对静态库和动态库有更深入的理解。