当前位置: 首页 > news >正文

十二、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) // 导出
#endif

extern "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++ 编程之路更加顺畅,就像大厨拥有了得心应手的工具,做出更加美味的菜肴一样!希望通过这篇博客,你能对静态库和动态库有更深入的理解。

相关文章:

  • HBuilder创建项目步骤
  • 虎跃办公AI:重构智能办公的「模型交响乐团」
  • conda如何安装和运行jupyter
  • ViT-Adapter
  • LVS+Keepalived+DNS 高可用项目
  • L36.【LeetCode题解】查找总价格为目标值的两个商品(剑指offer:和为s的两个数字) (双指针思想,内含详细的优化过程)
  • 【第三章】14-常用模块2-ngx_http_proxy_module
  • 【场景应用5】深入探讨去噪扩散概率模型及训练推理过程
  • 电路方案分析(二十)TPS63xxx系列DC/DC电源EMI PCB设计方案
  • Odoo 部署本地 把現時的excel計算表格部署上odoo 教程
  • 利用 pyecharts 实现地图的数据可视化——第七次人口普查数据的2d、3d展示(关键词:2d 、3d 、map、 geo、涟漪点)
  • 基于Yolov8的植物病虫害检测系统
  • Linux线程属性与多线程开发:API详解与实战代码解析
  • 【一起来学kubernetes】37、lstio使用详解
  • 【前端】webpack一本通
  • HTML入门—表格与表单设计
  • 十大PDF解析工具在不同文档类别中的比较研究
  • HTTP 协议-应用层
  • STM32蓝牙连接Android实现云端数据通信(电机控制-开源)
  • Unity UI中的Pixels Per Unit
  • 网站建设合同示范文本/软文代写网
  • 南京网站定制/福州seo排名公司
  • dede可以做视频网站/深圳网站建设开发公司
  • qq可以做公司免费网站/绍兴百度seo排名
  • 做指甲的网站/天津百度推广网络科技公司
  • 深圳龙岗区最新疫情/优化网站排名