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

C++中编译静态库与动态库

1.库的理解

库就是写好的现有的,成熟的,可复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。

本质上来说库是一种可执行代码的二进制形式是预编译代码的集合,可以被程序重新使用,能够被操作系统载入内存执行。

库有两种:静态库(.a、.lib)和动态库(.so、.dll)。所谓静态、动态是指链接。具体来说,二者链接的时间点不同,代码被载入的时刻不同,具体详见下文。

回顾一下,将一个程序编译成可执行程序的步骤:

2.源文件、编译、链接到可执行文件

源代码要经过上图中预编译(Processing)、编译(Compilation)、汇编(Assembly)、链接(Linking)等步骤生成可执行文件。

2.1编译

(1)预编译,即预处理,主要处理在源代码文件中以“#”开始的预编译指令,如宏展开、处理条件编译指令、处理#include指令等。

(2)编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析以及优化后生成相应的汇编代码文件。

(3)汇编是将汇编代码转变成机器可以执行的指令。

至此,C/C++源代码文件经过预编译、编译和汇编直接输出目标文件(.o文件)。这个过程也就是编译器所做的事(即将高级语言翻译成机器语言),比如我们用C/C+语言写的一个程序可以使用编译器将其翻译成机器可以执行的指令及数据。

现代的编译器将一个源代码文件编译成一个未链接的目标文件,然后由链接器最终将这些目标文件链接起来形成可执行文件。

2.2链接

程序设计的模块化是人们一直在追求的目标,因为当一个系统十分复杂的时候,我们不得不将一个复杂的系统逐步分割成多个小的系统以达到各个突破的目的。一个复杂的软件也是如此,人们把每个源代码模块独立地编译,然后按照需要将它们“组装”起来,这个组装模块的过程就是链接(Linking),链接的主要内容就是把各个模块之间相互引用的部分都处理好,使得各个模块之间能够正确地衔接。

3.静态链接与动态链接

3.1静态链接

最基本的静态链接过程如下图所示。每个模块的源代码文件(如.c)文件经过编译器编译成目标文件(Objet File,一般扩展名为.o或.obj), 目标文件和库(Library)一起链接形成最终可执行文件。

而最常见的库就是运行时库(Runtime Library),它是支持程序运行的基本函数的集合。库其实是一组目标文件的包,就是一些最常用的代码编译成目标文件后打包存放。

现代的编译和链接过程也并非想象中的那么复杂,它还是一个比较容易理解的概念。比如我们在程序模块main.c中使用另外一个模块func.c中的函数foo()。我们在main.c模块中每一处调用foo的时候都必须确切知道foo这个函数的地址,但是由于每个模块都是单独编译的,在编译器编译main.c的时候它并不知道foo函数的地址,所以它暂时把这些调用foo的指令的目标地址搁置,等待最后链接的时候由链接器去将这些指令的目标地址修正。如果没有链接器,须要我们手工把每个调用foo的指令进行修正,然后填入正确的foo函数地址。当func.c模块被重新编译, foo函数的地址有可能改变时,那么我们在main.c中所有使用到foo的地址的指令将要全部重新调整。这些繁琐的工作将成为程序员的噩梦。使用链接器,你可以直接引用其他模块的函数和全局变量而无须知道它们的地址,因为链接器在链接的时候,会根据你所引用的符号foo, 白动去相应的func.c模块查找foo的地址,然后将main.c模块中所有引用到foo的指令重新修正,让它们的目标地址为真正的foo函数的地址。这就是静态链接的最基本的过程和作用。

3.2动态链接

静态链接这种方法的确很简单,原理上很容易理解,实践上很难实现,在操作系统和硬件不发达的早期,绝大部分系统采用这种方案。

随着计算机软件的发展,这种方法的缺点很快就暴露出来了,那就是静态连接的方式对于计算机内存和磁盘的空间浪费非常严重。特别是多进程操作系统情况下,静态链接极大地浪费了内存空间。

想象一下每个程序内部除了都保留着printf()函数、scanf()函数、strlen()等这样的公用库函数,还有数量相当可观的其他库函数及它们所需要的辅助数据结构。

此外,静态链接对程序的更新、部署和发布也会带来很多麻烦,即一旦程序中有任何模块更新,整个程序就要重新链接、发布给用户。

比如一个程序有20个模块,每个模块1 MB,那么每次更新任何一个模块,用户就得重新获取这个20 MB的程序。如果程序都使用静态链接,那么通过网络来更新程序将会非常不便,因为一旦程序任何位置的一个小改动,都会导致整个程序重新下载。

要解决空间浪费和更新困难这两个问题最简单的办法就是把程序的模块相互分割开来,形成独立的文件,而不再将它们静态地链接在一起。

简单地讲,就是不对那些组成程序的目标文件进行链接,等到程序要运行时才进行链接。也就是说,把链接这个过程推迟到运行时再进行,这就是**动态链接(Dynamic Linking)**的基本思想。同样举个小例子:

还是以Program1和Program2为例,假设我们保留Programl.o、Program2.o和Lib.o三个目标文件。当我们要运行Program1这个程序时,系统首先加载Program1.o,当系统发现Program1.o中用到了Lib.o,即Program1.o依赖于Lib.o,那么系统接着加载Lib.o,如果Program1.0或Lib.o还依赖于其他目标文件,系统会按照这种方法将它们全部加载至内存。所有需要的目标文件加载完毕之后,如果依赖关系满足,即所有依赖的目标文件都存在于磁盘,系统开始进行链接工作。这个链接工作的原理与静态链接非常相似,包括符号解析、地址重定位等。完成这些步骤之后,系统开始把控制权交给Program1.o的程序入口处,程序开始运行。这时如果我们需要运行Program2,那么系统只需要加载Program2.o,而不需要重新加载Lib.o,因为内存中已经存在了一份Lib.o的副本,系统要做的只是将Program2.0和Lib.o链接起来,不同于静态链接,还需要再次加载Lib.o的副本。

4.静态库与动态库对比

结合上述静态链接与动态链接的对比,可以得到下面静态库与动态库的比较:

***静态库:包含在编译时链接到用户程序的代码,函数和数据都被编译进一个二进制文件(通常扩展名为.LIB)。在使用静态库的情况下,编译链接生成可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其它模块组合起来创建最终的可执行文件(.exe文件)。生成的可执行文件保留了自己的库代码副本。
***动态库(或共享库)包含旨在由多个程序共享的代码,由此动态库也称为共享库。库中的内容在运行时加载到内存中。每个可执行文件不维护其库的复制。使用它的时候往往提供两个文件:一个引入库和一个DLL。引入库包含被DLL导出的函数和变量的符号名,DLL包含实际的函数和数据。在编译链接可执行文件时,只需要链接引入库,DLL中的函数代码和数据并不复制到可执行文件中,在运行的时候,再去加载DLL,访问DLL中导出的函数。

这是使用静态库与动态库的说明。由下图可以看到静态库包含在可执行文件中。而动态库只需要在程序中创建一个符号表(库代码中引用的函数、变量)。

在运行时,动态库在现代操作系统中只被加载到内存中一次,并在依赖它的所有程序之间共享。相反,当使用静态库时,每个可执行文件都必须将库代码加载到内存中。当有多个可执行文件运行时,前者可以提高内存利用率。下图可以解释这种比较。

使用静态库会导致两个明显的缺点:

1. 增加应用程序的大小。如果应用程序包含多个可执行文件,问题会变得更糟。您最终可能会保留同一个库的多个副本。

2. 修改/升级库代码需要重新运行应用程序其他部分的编译/链接。这可能是部署/维护目的的痛苦。大多数时候,一个(非接口相关的)动态库升级不需要重新编译其他部分。

通常,由于上述原因,人们多数时候倾向于选择动态库而不是静态库。然而,动态库并不完美。他们对开发人员有自己的障碍——需要额外关注安装。与生成整体包的静态库不同,动态库必须位于适当的位置以确保可执行文件可以在运行时找到库。

-----静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库,因此体积较大。
-----动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在,因此代码体积较小。动态库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。带来好处的同时,也会有问题!如经典的DLL Hell问题。

静态和动态 C++ 库之间的差异10条

序号

比较维度

动态库

静态库

1

build程序

(编译+链接)

编译时:不需要

链接时:需要

编译时:需要

链接时:不需要

(链接发生在构建使用静态库的客户端可执行文件时)

2

二进制文件的本质

没有启动例程的可执行文件。

包含已解析的引用。

目标文件的存档。

所有部分都存在,但大多数引用未解决(本地引用除外)

3

生成可执行文件后需要吗?

需要

动态库需要与可执行文件一起打包,并且必须在可执行文件开始运行时调用(更具体地说,调用动态库提供的函数)

不需要

仅在构建可执行文件在链接阶段)才需要静态库。在运行可执行文件时不再需要,因为库代码已嵌入在应用程序中。

4

磁盘空间效率:磁盘上应用程序之间的代码共享

共享度高

同一个动态库可以在磁盘上的多个可执行文件之间共享。

共享度低

每个可执行文件都需要链接它的静态库的单独副本。这会导致磁盘上出现大量二进制文件副本,尤其是资源受限的移动设备。但是,如果每个应用程序只使用整个静态库的一小部分,磁盘空间效率仍然可以与单个大型 DLL 竞争。

5

内存效率

许多现代操作系统会尝试将动态库代码一次加载到内存中,并在所有需要它的应用程序之间共享。例如,一个 http 网络堆栈可能会在你的日历和笔记本应用程序之间共享。

如果 http 网络堆栈位于静态库中,则每个需要此功能的应用程序都将加载它自己的网络堆栈副本,并通常会影响运行时内存。

6

版本控制问题

可能存在

当应用程序使用的动态库版本与操作系统上存在的旧/新版本库冲突时,你可能会遇到问题。

不存在

由于所有库功能都链接到应用程序中,因此系统上的其他应用程序是否使用不同版本的静态库并没有关系。

7

提供更新/补丁

方便

如果用户希望使用动态库的新(ABI 兼容)版本对应用程序打补丁,他们只需从你那里获取一个新的 dll 并仅修补该 DLL,而无需build整个应用程序。

不太方便

整个应用程序将需要重新构建和修补。这对大型应用程序来说是个大问题,因为现在你需要通过网络提供更大的完整的更新文件。

8

控制加载

在某些系统中,应用程序通过系统调用(如(Windows 上的 LoadLibrary))明确控制何时加载和卸载库功能。这有助于在资源受限的系统上以有效的方式管理应用程序的内存。

不是

当应用程序启动时,整个库被加载到进程空间,并一直保留到应用程序关闭。

9

打包

复杂

在大多数系统中,需要一个单独的步骤来为应用程序创建清单/依赖清单并将其打包。

简单

默认情况下与应用程序/可执行文件本身一起分发 - 无需单独打包。

10

开发过程中的适用性

只有动态库中的功能需要重新编译。

繁琐

整个应用程序将需要重新编译。对于大型应用工具或像 Office 这样大的应用程序,如果所有功能都静态链接而不是在单独的 DLL 中,则可能需要数小时。

5.静态库与动态库的创建与使用

5.1 创建和使用静态库

在这个例子中,我们将创建一个具有一个倒数函数的lib库。库源包含头文件 my_math.h 和源文件 my_math.cpp:


#ifndef H_MY_MATH
#define H_MY_MATH// my_math.hdouble reciprocal(double d);#endif // H_MY_MATH
#include "my_math.h"
//my_math.cppdouble reciprocal(double d) {return 1.0 / d;
}
#include "my_math.h"
#include <iostream>
// main.cppint main(){std::cout << reciprocal(2.0) << std::endl;return 0;
}

头文件 my_math.h 包含在 main.cpp 中,它从库中调用函数:

在第一次编译中,我们将 my_math.cpp 视为一个普通的源文件,一切都按预期的那样:

g++ -c main.cpp -o main.o
g++ -c my_math.cpp -o my_math.o
g++ main.o my_math.o -o a.out
./a.out
0.5

现在让我们将 my_math 打包为静态库。该过程包括 2 个步骤。第 1 步是使用上面相同的命令生成目标文件 my_math.o。第 2 步涉及使用ar(Linux ar chive 实用工具)创建库文件:

ar cr libmy_math.a my_math.o

“cr”标志表示创建一个新的静态库文件。它后面首先是输出文件名的请求名称。注意输出的名称是“libmy_math.a”。在 Linux 中将文件命名为 libXXX.a 作为静态库是一种惯例,请务必这样做。当使用该库时,命令行工具实际上依赖于此约定以使链接器正常工作。

现在我们要使用静态库文件。一种方法是在 g++/gcc 链接命令中将该文件与其他目标文件放在一起。

g++ main.o libmy_math.a -o a.out

另一种更常用的方法是使用 (-L) 和库名称 (-l) 显式指定库路径:

g++ main.o -L. -l my_math -o a.out

这告诉编译器在路径 (.) 中查找名称为 libmy_math.a 的库。注意这里我们使用 -l my_math。链接器会将其视为指定文件名 libmy_math.a(记住我们刚才谈到的创建库的命名约定)。

我们可以通过删除库并运行来验证库是否已被复制到可执行文件中:

rm libmy_math.a 
./a.out
0.5

的确有用。我们刚刚创建了一个静态库并在我们的程序中使用它,验证了静态库的打包及使用。

5.2 创建和使用动态库

这次我们使用相同的示例代码,而不是创建一个动态库。这是执行命令:

g++ -shared -o libmy_math.so my_math.o

“-shared”标志指示生成共享库。同样,输出文件命名约定 libXXX.so 是必须的,稍后将由链接器使用。

类似于静态库,我们有两种方式来使用它。1. 将其作为链接器/编译器的输入。2.明确指定库位置(-L)和名称(-l):

g++ main.o my_math.so -o a.out
# or 
g++ main.o -L. -lmy_math -o a.out

简单吧?让我们运行它:

./a.out
./a.out: error while loading shared libraries: libmy_math.so: cannot open shared object file: No such file or directory

糟糕的是,我们遇到了一个错误(生成了一个可执行文件)。运行时试图找到一个名为 libmy_math.so 的共享库,但是提示找不到。到底发生了什么以及如何解决呢?

事实证明,用户必须向运行时的可执行文件或操作系统提供提示才能找到共享库 (libmy_math.so)。在 Linux 中有两种方式:

  1. 将共享库路径附加到环境变量 LD_LIBRARY_PATH。

  1. 在构建可执行文件时使用-rpath标志指定共享库路径。

我们再次测试一下:

  1. 将库路径添加到 LD_LIBRARY_PATH:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/cpp_tutorial/static_library
./a.out
0.5

在运行时,OS 会搜索 LD_LIBRARY_PATH 中的每个路径(以“:”分隔)以找到它需要的动态库。通过将路径附加到 LD_LIBRARY_PATH,我们修复了它。

2. 使用-rpath标志:

g++ main.o -L. -lmy_math -o a.out -Wl,-rpath,/home/cpp_tutorial/static_library
./a.out
0.5

这里的“-Wl 标志”意味着它后面的内容(以逗号分隔的标志列表)将被传递给链接器。在这种情况下,“-rpath /home/cpp_tutorial/static_library”被传递给链接器。链接器将此路径信息插入到可执行文件 (a.out) 自己的搜索路径中。这也有效。

比较这两种方法,修改 LD_LIBRARY_PATH 涉及更改影响所有程序的全局变量。使用-rpath通常是首选方式,因为它是本地更改,不会改变其他可执行文件的行为

参考资料

https://blog.csdn.net/qq_41073715/article/details/118516662

https://www.acodersjourney.com/cplusplus-static-vs-dynamic-libraries/

https://domiyanyue.medium.com/c-development-tutorial-4-static-and-dynamic-libraries-7b537656163e

相关文章:

C++中编译静态库与动态库

1.库的理解库就是写好的现有的&#xff0c;成熟的&#xff0c;可复用的代码。现实中每个程序都要依赖很多基础的底层库&#xff0c;不可能每个人的代码都从零开始&#xff0c;因此库的存在意义非同寻常。本质上来说库是一种可执行代码的二进制形式&#xff0c;是预编译代码的集…...

shell中sed命令用法

一、sed命令解析 1、sed工具概述 Stream EDitor&#xff0c;流式编辑器 - 非交互&#xff0c;基于模式匹配过滤及修改文本 - 逐行处理&#xff0c;并将结果输出到屏幕 - 可实现对文本的输出、删除、替换、复制、剪切、导入、导出等操作 2、命令格式解析 主要用法&#xff1a; …...

【VictoriaMetrics】VictoriaMetrics启停脚本

先看结果,启动VictoriaMetrics UI界面可访问...

高性能网络SIG月度动态:SMC 与 IBM 就扩展协议达成一致,virtio 支持 XDP 新特性

高性能网络 SIG&#xff08;Special Interest Group&#xff09; &#xff1a;在云计算时代&#xff0c;软硬件高速发展&#xff0c;云原生、微服务等新的应用形态兴起&#xff0c;让更多的数据在进程之间流动&#xff0c;而网络则成为了这些数据流的载体&#xff0c;在整个云时…...

【正点原子FPGA连载】第七章程序固化实验摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南

第七章程序固化实验 在前面的几个实验中&#xff0c;我们都是通过JTAG接口将FPGA配置文件和应用程序下载到MPSOC器件中。接下来我们将尝试把程序存储在非易失性存储器中&#xff0c;在上电或者复位时让程序自动运行&#xff0c;这个过程需要启动引导程序&#xff08;Boot Load…...

LeetCode-2335. 装满杯子需要的最短总时长【贪心,数学】

LeetCode-2335. 装满杯子需要的最短总时长【贪心&#xff0c;数学】题目描述&#xff1a;解题思路一&#xff1a;其实像一道数学题目。假设三个杯子x<y<z先分两种情况。第一种&#xff1a;xy<z&#xff0c;答案直接是最大的z。第二种&#xff1a;xy>z。先将x与y互相…...

基于 oss 框架的音频驱动

基于 oss 框架完成系统平台音频驱动的适配。 oss 框架可被多个平台应用&#xff0c;因此 oss 提供 OS 目录来存放平台文件&#xff08;比如&#xff1a;linux.c&#xff09;&#xff0c;该文件主要提供平台对 oss 框架封装后的相关接口。 以 Linux 为例&#xff0c;入口接口为…...

【golang】如何定制化zap日志库以及如何使用

Zap 日志 前言 本文主要介绍Go语言日志库如何简易定制化&#xff0c;以及如何在开发中使用。 为什么需要日志? 一个产品的诞生一定是因为有需求&#xff01;新技术大部分都是为了更加便利和实用而诞生的&#xff0c;日志也不例外。日志顾名思义就是对整个项目的事件进行记…...

如何将 Ubuntu 升级到 22.04 LTS Jammy Jellyfish

在本教程中,我们将详细介绍如何将你的 Ubuntu 系统升级到版本 22.04 Jammy Jellyfish,这是最新的长期支持版本。 Ubuntu 22.04 LTS Jammy Jellyfish 将于 2022 年 4 月 21 日发布。它是下个两年一次的长期支持(LTS)版本,因此值得注意,而且现在 Ubuntu 21.10 的用户可以升…...

ubuntu20.04安装docker与docker-compose

安装docker 查看系统发行版本 cat /proc/version1、更新apt包 sudo apt-get update2、安装必备的软件包以允许apt通过 HTTPS 使用存储库&#xff08;repository&#xff09;&#xff1a; sudo apt-get install ca-certificates curl gnupg lsb-release3、添加Docker官方版本…...

笔试题-2023-加特兰-数字IC设计【纯净题目版】

回到首页:2023 数字IC设计秋招复盘——数十家公司笔试题、面试实录 推荐内容:数字IC设计学习比较实用的资料推荐 题目背景 笔试时间:2022.07.27应聘岗位:数字电路设计工程师(SoC) - 2023届笔试时长:90min笔试平台:nowcoder牛客网题目类型:问答题(11道)主观评价 难易…...

动态内存管理

目录1.为什么要动态内存分配2.动态内存函数malloc](https://cplusplus.com/reference/cstdlib/malloc/?kwmalloc)和[freecallocrealloc3.使用动态内存要注意的几点对NULL的解引用对同一块动态内存多次释放free非动态开辟的内存使用free释放一块动态开辟内存的一部分一个函数中…...

Unsupervised Question Answering 简单综述

Unsupervised Question Answering by Cloze Translation, ACL 2019 随机从文本中抽取noun phrases或者named entity作为答案将答案部分mask掉&#xff0c;生成cloze question利用无监督翻译&#xff0c;将cloze question转化为natural question 缺点&#xff1a; 直接利用原句…...

智慧物流管理系统

智慧物流运用物联网、大数据、云计算、人工智能等技术优化物流决策过程。智慧物流获取、分析物流信息并做出决策&#xff0c;从商品源开始实时跟踪与管理&#xff0c;保证信息流快于商品流&#xff0c;实现信息与物质快速、高效、流畅地运转&#xff0c;集自动化、数字化、网络…...

单表查询--实例

#素材&#xff1a; 表名&#xff1a;worker-- 表中字段均为中文&#xff0c;比如 部门号 工资 职工号 参加工作 等 >CREATE TABLE worker ( >部门号 int(11) NOT NULL, >职工号 int(11) NOT NULL, >工作时间 date NOT NULL, >工资 float(8,2) NOT NULL, >政治…...

c语言递归 累和 ,累乘积,斐波那契数列,字符串长度

目录 递归使用场景 1:使用递归的方式计算 Sn123..100 2&#xff1a;计算 n&#xff01;n*(n-1)*(n-2)*......*1; 3:计算输出斐波那契数列前20项&#xff0c;并按每行4个数的格式输出(2019年&#xff09; 4&#xff1a; 用递归和非递归两种方式编写函数strlength()。该函数…...

数据与C(ASCII码,char)

目录 一.ASCII码讲解 二.非打印字符&#xff08;转义字符&#xff09; 三.扩展小知识 一.ASCII码讲解 char类型用于存储字符&#xff0c;从技术层面看&#xff0c;char时整数类型&#xff0c;因为char类型实际上存储的是整数而不是字符。计算机使用数字编码来处理字符&…...

第一个C语言代码(visual studin创建调试以及项目文件功能讲解)

这里我主要使用visual Studio进行编程 目录 一.创建项目 二.编写代码 1.代码编写 2.代码分析 3.main() 4.注释符 5.{} 花括号 6.声明 7.赋值 8.printf()函数 9.return 0; 一.创建项目 这里大家可能会比较疑惑&#xff0c;为啥都是C&#xff0c;没看见C的项目&…...

VIF原理

文章目录一、VIF公式和原理对于R方一般回归模型皮尔逊相关系数中的方差VIF原理&#xff1a;一、VIF公式和原理 所谓VIF方法&#xff0c;计算难度并不高。在线性回归方法里&#xff0c;应用最广泛的就是最小二乘法&#xff08;OLS&#xff09;&#xff0c;只不过我们对每个因子…...

nginx相关反爬策略总结笔记

引言 互联网站点的流量一部分由人类正常访问行为产生&#xff0c;而高达30%-60%的流量则是由网络爬虫产生的&#xff0c;其中一部分包含友好网络爬虫&#xff0c;如搜索引擎的爬虫、广告程序、第三方合作伙伴程序、Robots协议友好程序等;而并非所有的网络爬虫都是友好的&#x…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器

拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件&#xff1a; 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...

【Linux】Linux安装并配置RabbitMQ

目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的&#xff0c;需要先安…...