C++ 静态库与动态库的生成和使用:基于 VS Studio 生成 newmat 矩阵库的静态库与动态库

文章目录

  • Part.I Introduction
    • Chap.I 预备知识
    • Chap.II 静态库与动态库区分
  • Part.II 静态库的生成与使用 (newmat)
    • Chap.I 生成静态库
    • Chap.II 使用静态库
  • Part.III 动态库的生成与使用 (newmat)
    • Chap.I 生成动态库
    • Chap.II 使用动态库
  • Part.IV 文件内容
    • Chap.I test.cpp (静态库)
    • Chap.II test.cpp (动态库)
    • Chap.III 测试文件下载
  • Reference

Part.I Introduction

本文将详细地介绍 C++ 动态库和静态库,尽量让读者对他们有一个明晰的区分。然后基于一个实例(newmat 矩阵库)进行实际操作,以加深印象。

在这里插入图片描述

Chap.I 预备知识

在阅读下面的内容之前,首先需要了解如下概念和信息:

  • 动态链接库(Dynamic Link Library)或叫共享库(Shared Object)(这就是 dllso 文件后缀的由来)
  • 静态链接库(Static Link Library

有关库的一些文件

  • *.h 文件:C++ 头文件(文本文件),一般会包含函数的声明。
  • *.lib 文件:库文件(二进制文件),它可能是完整的静态库,里面有函数代码本身,在编译时直接将代码加入程序当中,应用程序直接使用;也有可能是动态库的导出声明,只包含头部信息。里面只有函数所在的 DLL 文件和文件中函数位置的入口,代码由运行时加载在进程空间中的 DLL 提供
  • *.dll 文件:动态库文件(二进制文件),Windows 下的动态库文件。
  • *.a 文件:UNIX 下的静态库文件
  • *.so 文件:UNIX 下的动态库文件

Chap.II 静态库与动态库区分

我们写程序的时候会需要加载库,一般需要先include头文件,然后再调用库函数,而库又分为两种,静态库(lib)和动态库(dll),那么这两种库有什么区别呢?

  • 静态库:我们的程序在链接时会把用到的静态库全部都链接进去,形成一个exe,这也导致我们的exe很大(程序是先编译,再链接库,最后形成exe
  • 动态库:程序在链接时在不再把整个库都链接进去,而是程序在运行过程中,用到哪个库,再加载哪个库,这就降低了exe的大小,但同时,运行速度也会变慢。

动态库与静态库优缺点分析
动态链接库优点 包括可减少程序的磁盘空间占用、方便更新库文件、共享库文件、提高程序间的互操作性、降低内存占用;缺点 包括需要确保运行环境中库文件的可用性。
静态链接库优点 包括编译后的可执行文件相对独立、移植性好、提高程序运行速度;缺点 包括每个可执行文件都包含一份静态库的拷贝、需要手动更新库文件。


静态链接库的使用

需要的文件:

  • *.h :头文件*.h中有函数的声明,使用静态链接库的项目需要引用(#include)文件才能编译通过
  • *.lib:包含了实际执行代码、符号表等等

加载*.lib的方法:

  • 用编译链接参数或者 VS 的配置属性来设置
  • 使用 pragma 编译语句,例如 pragma comment(lib,"a.lib")

动态链接库的使用——隐式调用

需要的文件

  • *.h :头文件*.h中有函数的声明,使用静态链接库的项目需要引用(#include)文件才能编译通过
  • *.lib:包含了函数所在的 *.dll 文件和文件中函数位置的信息。
  • *.dll:包含了实际执行代码、符号表等等

*.lib文件是『链接』时用的,加载方法同样有:

  • 用编译链接参数或者 VS 的配置属性来设置
  • 使用 pragma 编译语句,例如 pragma comment(lib,"a.lib")

*.dll文件是程序『运行』时用的,链接了lib之后形成的EXE可执行文件中已经有了dll的信息,所以只要dll放在和exe同一个目录下就可以了,运行时根据 EXE 需要自动加载dll中的函数。


动态链接库的使用——显示调用

需要的文件:只有动态链接库的 *.dll 文件,不需要*.h 文件和*.lib 文件。因为 LoadLibrary 之后可以使用 getProcAddress 来查找一个函数的地址从而调用该函数。


PS: 显式调用的前提是使用者需要知道想调用的函数的名字、参数、返回值信息,也就是说虽然编译链接用不上.h头文件,但是调用者编程时可能还是要看.h文件作参考来知道函数名字、参数、返回值信息


显式调用动态库步骤

  1. 创建一个函数指针,其指针数据类型要与调用的 DLL 引出函数相吻合。
  2. 通过 Win32 API 函数 LoadLibrary() 显式的调用 DLL,此函数返回 DLL 的实例句柄。
  3. 通过 Win32 API 函数 GetProcAddress() 获取要调用的 DLL 的函数地址,把结果赋给自定义函数的指针类型。
  4. 使用函数指针来调用 DLL 函数。
  5. 最后调用完成后,通过 Win32 API 函数 FreeLibrary() 释放DLL 函数。

下面将使用newmat矩阵库为例,基于 VS Studio 平台,详细介绍生成静态库和动态库的整个过程。newmat 戳我下载~

Part.II 静态库的生成与使用 (newmat)

Chap.I 生成静态库

1、新建一个『静态库』项目,名字取为LibNewmat_a

在这里插入图片描述

2、将默认创建的4个文件给排除掉,将 newmat 的 36 个文件复制到项目所在目录/src文件夹中。(注意x64)并将它们添加到项目中:右键项目→添加→现有项→进入srcCtrl+A全选→添加

在这里插入图片描述

3、选中项目右键→属性→C/C++→预编译头→不使用预编译头→应用→确定

在这里插入图片描述

4、选中项目右键→属性→C/C++→预处理器→预处理器定义→下拉三角编辑→加入_CRT_SECURE_NO_WARNINGS(这是针对newmat)进行的操作

在这里插入图片描述

5、快捷键 F6 生成,在x64/Debug目录下就生成了我们需要的*.lib

在这里插入图片描述

Chap.II 使用静态库

1、创建一个空项目,名字叫做test_a,添加一个cpp文件test.cpp

2、选中项目右键→属性→VC++ 目录→包含目录 把头文件所在目录贴进去;库目录把*.lib所在目录贴进去(看完下面的再决定要不要这样操作

在这里插入图片描述

PS:最好不要在这里加包含目录和库目录,这里时全局的(我是为了截一个图,懒狗一个)。下面是比较合适的操作:
包含目录(头文件所在目录):右键『属性』→『C/C++』→『常规』→『附加包含目录』
库目录(lib 文件所在目录):右键『属性』→『链接器』→『常规』→『附加库目录』

3、将Part.IV__Chap.I test.cpp的内容复制到文件test.cpp

4、快捷键F5得到运行结果

在这里插入图片描述

Part.III 动态库的生成与使用 (newmat)

Chap.I 生成动态库

1、新建一个『动态库』项目,名字取为LibNewmat_so

在这里插入图片描述

2、将默认创建的4个文件给排除掉,将 newmat 的 36 个文件复制到项目所在目录/src文件夹中。(注意x64)并将它们添加到项目中:右键项目→添加→现有项→进入srcCtrl+A全选→添加

在这里插入图片描述

3、选中项目右键→属性→C/C++→预编译头→不使用预编译头→应用→确定

在这里插入图片描述
4、选中项目右键→属性→C/C++→预处理器→预处理器定义→下拉三角编辑→加入_CRT_SECURE_NO_WARNINGS(这是针对newmat)进行的操作

在这里插入图片描述
5、快捷键 F6 生成,在x64/Debug目录下就生成了我们需要的*.dll

在这里插入图片描述

Chap.II 使用动态库

基于上面的操作我们可以看到:只生成了dll文件,没有生成lib文件,这是因为 newmat 库本身没有导出 (__declspec(dllexport)) 任何方法、类等,所以生成的 DL L不需要 lib 文件来记载导出符号。那这种情况下只能显示调用了,如何操作呢?浅试了一下,不会比较复杂的显式调用,暂时放弃。所以本小节后面的部分不必看了


1、创建一个空项目,名字叫做test_so,添加一个cpp文件test.cpp。(注意x64

在这里插入图片描述

2、将Part.IV__Chap.II test.cpp的内容复制到文件test.cpp

如何使用 dll 中的类型呢?求大佬指点!!

Part.IV 文件内容

Chap.I test.cpp (静态库)

/// \ingroup newmat
///@{/// \file nm_ex1.cpp
/// Very simple example 1.
/// Invert a 4 x 4 matrix then check the result#define WANT_STREAM       // include iostream and iomanipulators#include "newmatap.h"     // newmat advanced functions// should not be required for this example// included because it seems to help MS VC6// when you have namespace turned on#include "newmatio.h"     // newmat headers including output functions#pragma comment(lib,"LibNewmat_a.lib")
#ifdef use_namespace
using namespace RBD_LIBRARIES;
#endifint my_main()                  // called by main()
{Tracer tr("my_main ");      // for tracking exceptions// declare a matrixMatrix X(4, 4);// load values row by rowX.row(1) << 3.7 << -2.1 << 7.4 << -1.0;X.row(2) << 4.1 << 0.0 << 3.9 << 4.0;X.row(3) << -2.5 << 1.9 << -0.4 << 7.3;X.row(4) << 1.5 << 9.8 << -2.1 << 1.1;// print the matrixcout << "Matrix X" << endl;cout << setw(15) << setprecision(8) << X << endl;// calculate its inverse and print itMatrix Y = X.i();cout << "Inverse of X" << endl;cout << setw(15) << setprecision(8) << Y << endl;// multiply X by its inverse and print the result (should be near identity)cout << "X * inverse of X" << endl;cout << setw(15) << setprecision(8) << (X * Y) << endl;return 0;
}// call my_main() - use this to catch exceptions
// use macros for exception names for compatibility with simulated exceptions
int main()
{Try{ return my_main(); }Catch(BaseException) { cout << BaseException::what() << "\n"; }CatchAll{ cout << "\nProgram fails - exception generated\n\n"; }return 0;
}///@}

Chap.II test.cpp (动态库)

半成品没有跑通

/// \ingroup newmat
///@{/// \file nm_ex1.cpp
/// Very simple example 1.
/// Invert a 4 x 4 matrix then check the result#define WANT_STREAM       // include iostream and iomanipulators#include <iostream>
#include <windows.h>//#include "newmatap.h"     // newmat advanced functions
//                          // should not be required for this example
//                          // included because it seems to help MS VC6
//                          // when you have namespace turned on
//
//#include "newmatio.h"     // newmat headers including output functions#ifdef use_namespace
using namespace RBD_LIBRARIES;
#endifint my_main()                  // called by main()
{HINSTANCE hInst = LoadLibrary(L"LibNewmat_so.dll");   //加载dll库typedef void(*Sub)();//函数指针Sub PrintHello = (Sub)GetProcAddress(hInst, "PrintHello");//加载库函数Tracer tr("my_main ");      // for tracking exceptions// declare a matrixMatrix X(4, 4);// load values row by rowX.row(1) << 3.7 << -2.1 << 7.4 << -1.0;X.row(2) << 4.1 << 0.0 << 3.9 << 4.0;X.row(3) << -2.5 << 1.9 << -0.4 << 7.3;X.row(4) << 1.5 << 9.8 << -2.1 << 1.1;// print the matrixcout << "Matrix X" << endl;cout << setw(15) << setprecision(8) << X << endl;// calculate its inverse and print itMatrix Y = X.i();cout << "Inverse of X" << endl;cout << setw(15) << setprecision(8) << Y << endl;// multiply X by its inverse and print the result (should be near identity)cout << "X * inverse of X" << endl;cout << setw(15) << setprecision(8) << (X * Y) << endl;FreeLibrary(hInst);             //释放库return 0;
}// call my_main() - use this to catch exceptions
// use macros for exception names for compatibility with simulated exceptions
int main()
{Try{ return my_main(); }Catch(BaseException) { cout << BaseException::what() << "\n"; }CatchAll{ cout << "\nProgram fails - exception generated\n\n"; }return 0;}///@}

Chap.III 测试文件下载

有关上面的测试文件,笔者进行了整理并上传至 CSDN 资源,感兴趣的朋友可戳我免费下载。文件树如下:

newmat_lib_dll
├─DLL_project			
│  ├─LibNewmat_so		// 生成的动态库 dll
│  └─test_so			// 测试动态库 cpp 文件,半成品
├─LIB_project
│  ├─LibNewmat_a		// 生成的静态库 lib
│  └─test_a				// 测试静态库 cpp 文件
└─newmat_src			// newmat 库源码

Reference

  • C++ 静态库和动态库的创建和使用及区别
  • 动态链接库和静态链接库的区别

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/588862.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

探索iPhone GPU架构:了解其硬件设计与特性

摘要 了解你的显卡对于在电脑上玩现代图形要求高的游戏非常重要。本文介绍了如何轻松查看你的显卡型号以及为什么显卡在玩电脑游戏时如此关键。 引言 随着电脑游戏的发展&#xff0c;现代游戏对硬件性能的要求越来越高。十年前发布的显卡已经无法满足当前游戏的需求。因此&…

鸿蒙分布式音乐播放-如何完成播放、暂停、上一曲、下一曲功能

介绍 本示例使用fileIo获取指定音频文件&#xff0c;并通过AudioPlayer完成了音乐的播放完成了基本的音乐播放、暂停、上一曲、下一曲功能&#xff1b;并使用DeviceManager完成了分布式设备列表的显示和分布式能力完成了音乐播放状态的跨设备分享。 本示例用到了与用户进行交…

《书生·浦语大模型全链路开源开放体系》学习笔记

书生浦语大模型全链路开源开放体系-学习笔记 大模型成为发展通用人工智能的重要途径专用模型通用大模型 书生大模型开源历程InternLM2回归语言建模的本质主要亮点性能全方位提升强大的内生计算能力 从模型到应用典型流程全链条开源开放体系数据数据集获取预训练微调XTuner 评测…

pymc,一个灵活的的 Python 概率编程库!

目录 前言 安装与配置 概率模型 贝叶斯推断 概率分布 蒙特卡罗采样 贝叶斯网络 实例分析 PyMC库的应用场景 1. 概率建模 2. 时间序列分析 3. 模式识别 总结 前言 大家好&#xff0c;今天为大家分享一个超强的 Python 库 - pymc Github地址&#xff1a;https://gith…

第六十二:flex布局踩过的坑

flex布局好久不用了&#xff0c;今天踩过的坑记载一下&#xff1a; display:flex&#xff0c;加上了justify-content: space-between;导致上边三个平分了但是下边两个在两边&#xff0c;如下图&#xff1a; 其实最简单的方法就是去掉justify-content: space-between&#xff0c…

文件夹无法打开?教你轻松应对数据恢复挑战

在日常办公和生活中&#xff0c;电脑中的文件夹承载着大量的文件和数据&#xff0c;是我们不可或缺的工作伙伴。然而&#xff0c;有时我们可能会遇到一个令人头疼的问题——文件夹无法打开。这不仅会阻碍我们的正常工作进度&#xff0c;还可能导致重要数据的丢失。那么&#xf…

界面控件DevExtreme JS ASP.NET Core 2024年度产品规划预览(一)

在本文中我们将介绍今年即将发布的v24.1附带的主要特性&#xff0c;这些特性既适用于DevExtreme JavaScript (Angular、React、Vue、jQuery)&#xff0c;也适用于基于DevExtreme的ASP.NET MVC/Core控件。 注意&#xff1a;本文中列出的功能和特性说明官方当前/预计的发展计划&a…

厨房装修新趋势,6个必看设计。福州中宅装饰,福州装修

厨房是家庭中最重要的区域之一&#xff0c;因此装修设计非常重要。现在&#xff0c;人们更加注重厨房的功能性和美观性&#xff0c;因此新旧设计交替成为了一种趋势。 01. 以前&#xff1a;普通插座 后期因电器过多&#xff0c;插座数量不够&#xff0c;使用插线板不仅显得混…

归并排序和分治

归并排序 归并排序是利用归并的思想实现的排序方法&#xff0c;该算法采用经典的分治策略&#xff08;分治法将问题分成一些小的问题然后递归求解&#xff0c;而治的阶段则将分的阶段得到的各答案"修补"在一起&#xff0c;即分而治之)。 分而治之 可以看到这种结构…

Unity Mesh 生成图形(二)

一、概述 Unity 的 Mesh 是用于表示三维物体的网格数据结构。它是由一系列顶点和三角形组成的网格&#xff0c;用于描述物体的形状和外观。 Mesh 是由顶点、三角形和其他相关信息组成的&#xff0c;它用于在 Unity 中创建和渲染三维对象。顶点是网格的基本构建单元&#xff0…

Linux 设备树: 设备树节点与属性在 dtb 文件中的存储

前言 当前新版本的 Linux 内核 设备驱动框架&#xff0c;与设备树&#xff08;Device Tree&#xff09;结合密切&#xff0c;整体 设备树的设备驱动框架&#xff0c;比较的庞大&#xff0c;但又非常的经典。 一个个的 设备树解析函数&#xff0c;都是前人【智慧】的结晶&#…

go: go.mod file not found in current directory or any parent directory.如何解决?

这个错误表明你正在执行 go get 命令&#xff0c;但是当前目录或任何父目录中都找不到 go.mod 文件。这可能是因为你的项目还没有使用 Go Modules 进行管理。 要解决这个问题&#xff0c;有几种方法&#xff1a; go mod init <module-name> 其中 <module-name>…