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

news2024/10/7 12:23:19

文章目录

  • 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;
#endif


int my_main()                  // called by main()
{
    Tracer tr("my_main ");      // for tracking exceptions

    // declare a matrix
    Matrix X(4, 4);

    // load values row by row
    X.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 matrix
    cout << "Matrix X" << endl;
    cout << setw(15) << setprecision(8) << X << endl;

    // calculate its inverse and print it
    Matrix 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;
#endif


int 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 matrix
    Matrix X(4, 4);

    // load values row by row
    X.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 matrix
    cout << "Matrix X" << endl;
    cout << setw(15) << setprecision(8) << X << endl;

    // calculate its inverse and print it
    Matrix 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.coloradmin.cn/o/1573870.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux常用目录结构(目录命令)--6986字详谈

前面与大家讨论了linux的发展与由来&#xff08;这一块挺多的&#xff0c;小编还没有编写完成&#xff0c;希望大家理解&#xff09;&#xff0c;紧接着谈到了vmware安装及运行所存在的故障&#xff08;鉴定错误&#xff0c;虚拟机没有网&#xff0c;蓝屏等常见现象的总结及处理…

学透Spring Boot — 004. Spring Boot Starter机制和自动配置机制

如果你项目中一直用的是 Spring Boot&#xff0c;那么恭喜你没有经历过用 Spring 手动集成其它框架的痛苦。 都说 Spring Boot 大大简化了 Spring 框架开发 Web 应用的难度&#xff0c;这里我们通过配置 Hibernate 的两种方式来深刻体会这一点&#xff1a; 使用 Spring 框架集…

centos7.2系统部署ZooKeeper集群和Kafka集群(集群应用系统商城前置环境)

本次实验将使用centos7.2系统部署部署ZooKeeper集群因为Kafka依赖于ZooKeeper&#xff0c;所以我们一并进行部署。 实验所示的资源软件已上传至百度网盘&#xff0c;需要自取。 链接&#xff1a;https://pan.baidu.com/s/1a-7_iAIX0DBAMkF9bhiTcA?pwd2333 提取码&#xff1…

C++:stack类和queue类

stack的介绍和使用 1. stack 是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的插入与提取操作。 2. stack 是作为容器适配器被实现的&#xff0c;容器适配器即是对特定类封装作为其底层的容器&#xff0c;并…

壁纸小程序Vu3(预览页面:弹窗)

1.展示跳转后的分类列表图片 classlist.vue <template><view class"classlist"><view class"content"><navigator class"item" v-for"item in 10"><image src"../../common/images/64.png" mode…

DFS(排列数字、飞机降落、选数、自然数的拆分)

注&#xff1a;1.首先要知道退出条件 2.还原现场 典型&#xff1a;全排列 题目1&#xff1a; 代码&#xff1a; #include<bits/stdc.h> using namespace std; int a[1005],p[1005],v[1005]; int n; void dfs(int x) {//此次dfs结束条件,即搜到底 if(xn1){for(int i1;i&…

AcWing刷题-计算系数

计算系数 代码&#xff1a; MOD 10007 a, b, k, n, m [int(x) for x in input().split()]def pow(a, n):r 1 % MODwhile n:if n & 1: r r * a % MODa a * a % MODn >> 1return rdef C(n, m):r 1 % MODfor i, j in zip(range(n, -1, -1), range(1, m 1)):r …

CLR学习

视频链接&#xff1a;《CLR十分钟》系列之CLR运行模型_哔哩哔哩_bilibili 什么是 CLR 公共语言运行时&#xff08;Common Language Runtime CLR&#xff09; 是一个可有多种编程语言使用的 运行时&#xff0c;CLR 的核心功能&#xff08;比如 内存管理&#xff0c;程序集加载…

解锁网络安全新境界:雷池WAF社区版让网站防护变得轻而易举!

网站运营者的救星&#xff1a;雷池WAF社区版 ️ 嘿朋友们&#xff01;今天我超级激动要跟你们分享一个神器——雷池WAF社区版。这个宝贝对我们这帮网站运营者来说&#xff0c;简直就是保护伞&#xff01; 智能语义分析技术&#xff1a;超级侦探上线 先说说为啥我这么稀饭它。雷…

Qt环形颜色选择控件, 圆环颜色选择器

参考文章Qt编写自定义控件&#xff1a;环形颜色选择控件_qconicalgradient圆环渐变-CSDN博客 感谢作责提供的方法&#xff0c;下面程序的基础思路同参考文章。 为了更方便使用&#xff0c;这个选择器是基于64色表的&#xff0c;会显示选中的索引和色值。颜色选择时计算方式也…

Vite源码学习--调试源码

简介 当我们开始构建越来越大型的应用时&#xff0c;需要处理的 JavaScript 代码量也呈指数级增长。包含数千个模块的大型项目相当普遍。基于 JavaScript 开发的工具就会开始遇到性能瓶颈&#xff1a;通常需要很长时间&#xff08;甚至是几分钟&#xff01;&#xff09;才能启…

接口日志表结构

表&#xff1a;ZTALL_IFLOG MANDT MANDT CLNT 3 0 0 客户端 UUID SYSUUID_C32 CHAR 32 0 0 16-byte UID in 32 chars (hexadecimal) IFSNR ZE_IFSNR CHAR 30 0 0 接口编号(系统ID流水号) FUNCNAME RS38L_FNAM CHAR 30 0 0 功能模块的名称 STATUS BAPI_MTYPE CHAR 1 0 0 消息类…

【计算机毕业设计】电影购票系统——后附源码

&#x1f389;**欢迎来到我的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 一名来自世界500强的资深程序媛&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 在深度学习任务中展现出卓越的能力&#xff0c;包括但不限于…

linux--进程创建

执行了3次ps -f ,ps -f的父进程的ID(PPID)都是一样的,即bash. 实际上Linux上这个bash就是不断的复制自身,然后把复制出来的用exec替换成想要执行的程序(比如ps); 运行ps,发现ps是bash的一个子进程;原因就是bash把自己复制一份,然后替换成ps; 替换,这里就体现了写时拷贝的意义,…

学习vue3第十四节 Teleport 内置组件介绍

<Teleport></Teleport> 作用目的&#xff1a; 用于将指定的组件或者元素传送到指定的位置&#xff1b; 通常是自定义的全局通用弹窗&#xff0c;绑定到 body 上&#xff0c;而不是在当前元素上面&#xff1b; 使用方法&#xff1a; 接收两个参数 to: 要将目标传…

Ceph学习 - 1.存储知识

文章目录 1.存储基础1.1 基础知识1.1.1 存储基础1.1.2 存储使用 1.2 文件系统1.2.1 简介1.2.2 数据存储1.2.3 存储应用的基本方式1.2.4 文件存储 1.3 小结 1.存储基础 学习目标&#xff1a;这一节&#xff0c;我们从基础知识、文件系统、小节三个方面来学习。 1.1 基础知识 1.…

Qt中的网络通信

C没有封装专门的网络套接字的类&#xff0c;因此C只能调用C对应的API&#xff0c;而在Linux和Windows环境下的API都是不一样的 Qt作为一个C框架提供了相关封装好的套接字通信类 在Qt中需要用到两个类&#xff0c;两个类都属于network且都是属于IO操作&#xff0c;只不过这两个类…

第十四届蓝桥杯C/C++大学B组题解(一)

1、日期统计 #include <bits/stdc.h> using namespace std; int main() {int array[100] {5, 6, 8, 6, 9, 1, 6, 1, 2, 4, 9, 1, 9, 8, 2, 3, 6, 4, 7, 7,5, 9, 5, 0, 3, 8, 7, 5, 8, 1, 5, 8, 6, 1, 8, 3, 0, 3, 7, 9,2, 7, 0, 5, 8, 8, 5, 7, 0, 9, 9, 1, 9, 4, 4, 6,…

Golang | Leetcode Golang题解之第8题字符串转换整数atoi

题目&#xff1a; 题解&#xff1a; func myAtoi(s string) int {abs, sign, i, n : 0, 1, 0, len(s)//丢弃无用的前导空格for i < n && s[i] {i}//标记正负号if i < n {if s[i] - {sign -1i} else if s[i] {sign 1i}}for i < n && s[i] >…

DFS序列

什么是DFS序 DFS序是指对一棵树进行DFS时&#xff0c;每个节点被访问到的顺序。DFS序分成两个部分&#xff1a;进入该节点的顺序和退出该节点的顺序。 如何求DFS序 对于DFS中当前节点 1&#xff1a;计数 2&#xff1a;进入当前节点的顺序等于当前计数 3&#xff1a;想所有…