【Linux内核系列】:动静态库详解
🔥 本文专栏:Linux
🌸作者主页:努力努力再努力wz
💪 今日博客励志语录:
有些鸟儿是注定是关不住的,因为它们的每一片羽翼都沾满了自由的光辉
★★★ 本文前置知识:
编译与链接的过程
1.引入
那么在正式接触动静态库之前,那么我们得先有一个前置知识的储备,那么便是从源文件形成一个可执行文件的一个过程,那么我们自己经常在诸如VS或者Dev c++平台上编写我们的代码形成可执行程序,那么你是否清楚的了解你编写的源文件到最终的可执行文件的一个过程呢?如果你对此过程感到有点陌生,没关系,那么我们就先来对该过程进行一个简单的回顾。
那么我们要形成一个可执行文件,那么该可执行文件就好比我们下厨做饭最终要在桌子上做的一道菜,那么要成功完成好这一道菜,那么我们手上必须有该菜所需的原材料和调料以及有了原材料和调料之后我们接下来做菜的一个个步骤或者环节我们得掌握清楚,其中对于我们可执行程序来说,那么它所谓的“原材料”就是保存该程序调用的函数的声明所在的头文件以及保存该函数定义所在的源文件以及主函数的代码所在的源文件,那么它依赖这三种源文件,那么有了这三种源文件之后,那么要形成最终的可执行程序,便要经历两个大的环节,那么便是编译和链接,其中的链接环节对于们要掌握动静态库来说,非常重要,那么我们先来谈第一个阶段,也就是编译:
那么编译这个大环节其实可以分解为四个步骤,分别是预处理以及语法检查和编译以及最后的汇编,那么首先我们的头文件以及源文件会经历第一个环节,便是预处理,那么在预处理阶段,我们源文件的第一行会有一个#include XXX的语句,那么该语句就是引用对应的头文件,那么此时预处理阶段就会将该语句替换为引用的对应的头文件的内容,那么将头文件的内容,也就是保存的函数以及变量的声明给展开到引用该头文件的源文件中,那么这个工作就是头文件展开,并且预处理阶段还会进行注释的消去以及宏替换等等,那么此时经过预处理阶段的源文件就会生成对应的后缀名为.i的临时文件,那么由于头文件的内容被复制拷贝到引用它的源文件中,那么头文件就不再参与后序的所有流程了,而此时预处理阶段生成的每一个临时.i文件中的内容还是未经编译的代码。
经过预处理阶段之后,下一个环节便是语法以及语义检查等,那么这个阶段所做的工作,我们就可以简单理解为编译器会检查每一个文件的每一行代码是否有语法错误,那么知道这点便足矣,至于它是如何检查的,以及该阶段会构建一个语法树,那么这些都是编译原理的知识,那么本文便不再对此赘述,读者感兴趣下来可以自行了解
那么经过语法检查之后,便顺利进入第三个环节,便是编译,此时会将每一个文件的代码给转换成会汇编码,并且会对每一个文件生成一个符号表,那么该符号表则是记录了每一个文件的全局变量以及全局函数的声明以及他们所对应的定义的位置或者说地址,那么一定要注意的就是该地址不是物理内存中的地址,因为我们现在还在编译阶段,那么此时都还没生成可执行文件,更别说加载到内存了,所以不存在所谓的分配物理地址,这点一定要注意理解,而这个地址是逻辑上的地址,也就是该函数的定义在文件模块中的偏移量,因为全局函数或者变量意味着它们会被其他文件给调用,那么就一定要记录其定义所在的位置,从而在符号表中从而能够寻找到,那么这里每一个文件都会有一个符号表,那么有的文件可能只看到函数或者变量的声明没看到定义,那么此时该文件对应的符号表对应的该函数的定义所在的位置就会为空,但是编译器不会进行所谓的报错处理,因为编译器知道它为空不一定代表着它没有定义可能是它的定义不在该文件当中,那么此时它会被标记为未解析,会在链接阶段进一步完善,最后经过编译阶段之后,那么此时每一个.i文件会生成一个后缀名为.s的文件
编译的最后一个阶段便是汇编了,那么此时会将每一个.s文件中的汇编码给转换成机器码也就是二进制序列,那么此时经过汇编阶段之后,那么.s文件会最终生成一个后缀名为.o的文件,那么至此编译阶段就结束了
第二个大阶段便是链接,那么链接这个环节十分的重要,和我们之后的动静态库的内容有非常大的关联,那么我们知道在编译阶段,最初的所有的头文件以及源文件最终会形成一个.o的文件,而链接阶段所做的做核心的工作就是将这些.o文件给合并成一个文件,那么该文件就是可执行文件,那么其中涉及的过程就包括将之前每一个文件的符号表合成生成一张全局的符号表,那么链接阶段的详细过程,我会在后文补充,那么我们脑海中有一个简单的理解即可
源文件(.c/.cpp) → [预处理] → 预处理文件(.i) → [编译] → 汇编文件(.s) → [汇编] → 目标文件(.o) → [链接] → 可执行文件
2.库
那么我们有了生成可执行文件的一个大致的流程,那么现在假设有这么一个场景,你要编写一个功能类似于计算器的一个程序,能够实现简单的加减乘除,那么此时你在源文件中编写了加减乘除的对应的四个函数的定义,然后在头文件中编写了该4个函数的声明,最终成功实现了一个简易的计算器程序,而与此同时其他人写的程序此时有相应的需求比如需要计算两个数相加或者相乘,那么他们看到你已经实现了相应功能模块的函数并且认为你写的非常完善非常好,那么他们认为没必要再自己造轮子重新写一份相应的函数,直接偷懒调用你的写好的函数就可以了,那么此时对于你来说,你是采取直接将头文件以及源文件直接发送给他们还是说采取其他的方式?
那么假设你和需要你提供源代码的那几个人是好兄弟或者说是同事关系,那么在这种情况下,你假设选择第一种方式,也就是将写好的加减乘除的四个函数所对应的头文件以及源文件给打包发给你的好伙伴,根据我们上文所讲的生成可执行文件的一个流程,我们知道你的好伙伴获取到你的头文件以及源文件之后,那么它们只能从头开始也就是得将这些文件先编译最后在链接,那么要知道假设此时做的是一个大型的项目,那么该项目涉及到的源文件以及代码量是很大的,那么此时对不起,你的好伙伴如果重新编译再链接的话,那么他们就需要等待较长时间的编译直到生成最终的可执行文件
所以为了提高效率,那么聪明的你选择了另一种方式,那么就是你将源文件先只进行编译形成.o文件,那么你再将程序需要的.o文件一起打包到一个文件夹,那么该文件夹就是一个.o文件的集合,而这个文件夹我们有一个专业的术语,那就是库,那么有了库之后,我们在将库和对应的头文件发给你的好伙伴,那么你的好伙伴就只需要完成链接工作,那么就能生成最后的可执行文件了。
而如果说你和需要你提供源代码的那几个人是陌生人或者说来自不同的公司,那么此时你就只能采取第二种而不是第一种,不采取第一种不是因为你不想坑人家,而是你直接将保存定义的源代码文件给别人了,那么别人就能够看到定义,那么如果你写的这些函数是你们公司的核心业务所需要的函数,那么别人看到之后,就可以直接窃取到,而采取第二种不仅是因为提升了编译的效率,更为重要的是你保存定义的源文件一旦形成.o文件之后,那么此时对方打开该.o文件,看到的全是一堆二进制码,也就意味着对面只能获取你函数的声明,他们只能知道怎么调用你这个函数也就是函数名以及参数列表是个啥,但是对方是不知道你这函数是怎么实现的,那么这就是我们动静态库一个非常常见的引用场景
那么我们自己写代码的时候,我们经常公式的在代码开头写#include<stdio.h>语句,那么这个所谓的stdio.h是c语言的标准库,其保存了c库函数的声明,那么c库函数的定义则是系统的链接器有保存了c库的所在的路径,那么它能够从这些路径找到对应的库然后链接到我们的可执行程序中,那么这些库就是所谓的第一方库,也就是我们每一个人都能够用到的,那么像我们上文举得那个例子,也就是你自己写了一个加减乘除的函数然后打包成库,那么这就是所谓的第三方库,也就是我们用的是别人提供的库,而其中第三方库有两种,也就是我们本文的重点,便是动态库和静态库。
3.静态库
静态库是什么
那么前面铺垫了这么久就是为了引入这个动静态库,那么我们先来认识一下静态库,那么静态库的关键就是它的这个"静"字,那么相信你看完下文,你便能知道它为何为“静"
那么我们知道了要形成可执行程序,假设我们手上持有了写好的头文件以及源文件,那么我们知道我们可以将我们的源文件给先编译成.o文件,然后我们只需要将.o文件给打包成库,然后再与头文件一起封装交给别人来进行链接即可
那么对于之后下文所讲的动态库,那么他们其实本身都是将保存定义的源文件进行一个编译形成一个个.o文件然后整体打包成库,而之所以他们不同,就是根链接的方式有关,那么对于静态库来说,此时编译器有了我们编译好的.o文件集合的库,那么此时它会扫描我们主函数也就是main.o对应的符号表,来确定哪些函数没有对应的定义,那么接着它便会扫描静态库当中的.o文件的符号表,看是否有匹配的函数定义,如果有的话,那么此时编译器就会将文件中的相应函数的定义的代码段给直接拷贝到可执行文件当中,所以在运行可执行文件的时候,就不需要系统的链接器到系统的保存默认路径下去寻找相应的库,因为调用的函数的声明以及定义都在该执行文件当中,那么这就是静态链接
要注意的一些细节就是,我们假设我们该程序只调用了比如静态库中某一个.o文件中的其中几个函数而不是所有该.o文件的函数,那么我们此时编译器不会将调用函数的定义所在的.o文件全部给拷贝复制,而是按需复制,将该文件中被真正调用的函数的定义的内容给拷贝复制过去
静态库的优点也就很明显,也就是不用担心库缺失,假设你不小心删除了静态库,那么静态库被删除了一点也不影响你的可执行文件的正常运行,因为编译器已经将静态库的内容全部拷贝复制到可执行文件当中,而这点则是动态库所做不到的,我在下文会说到,那么缺点就是很明显,那么可执行文件由于有了静态库文件的拷贝,那么体积就会很大
实现一个静态库
那么这里我们知道在Linux系统下,静态库的库名的标准是libXXX.a,那么任何静态库必须遵循这个标准,也就是得有固定前缀lib以及固定后缀.a,那么接着系统的连接器会从默认的以下的路径去搜索静态库:
/usr/lib:存放系统级静态库和动态库。
/lib:核心系统库(如基础 C 库)。
/usr/local/lib:用户自行安装的第三方库。
所以我们的静态库的命名规则得按照libXXX.a来命名,其中的XXX是自己自定义的库名,那么现在我们手头持有一个包含源文件以及头文件的project的目录,那么它的具体结构是这样的:
project/
├── main.c
├── include/
│ └── mylib.h
├── src/
│ └── mylib.c
└── Makefile
那么我们的makefile和project处于同一级目录下,其中我们的mylib.h则是保存我们main.c调用的函数的声明而mylib.c则是保存调用函数的定义
其中mylib.h头文件代码内容:
#pragma once
#include<stdio.h>
int add(int x,int y);
mylib.c源文件代码内容:
#include"mylib.h"
int add(int x,int y)
{return x+y;
}
main.c源文件代码内容:
#include"mylib.h"
int main()
{int ret=add(10,20);printf("%d\n",ret);return 0;
}
而生成目标可执行文件文件所在目录结构我们希望是这样的:
└── output/
├── myprogram
├── libmylib.a
└── include/
└── mylib.h
那么接着我们就用makefile来构建我们的可执行程序,那么我们首先将我们的各个目录以及可执行文件名在makefile分别定义一个变量来保存,然后我们先从可执行文件也就是myprogram来进行构建,那么myprogram依赖两个文件,分别是main.o以及libmylib.o,而libmylib.o是我们自己实现的一个静态库
LIB=libmylib.a
SRC_DIR=src
INC_DIR=include
EXE=myprogrma
OUT_DIR=output
那么接着makefile会检查当前目录下是否有main.o以及libmylib.o,那么如果没有,那么接着它会寻找到main.o以及libmylib.o的一个实现,然后在当前目录下生成main.o以及libmylib.o,
那么对于main.o文件,我们接下来要给编写对应的依赖关系以及依赖方法,那么它依赖的文件是main.c,那么由于main.c和makefile文件不在同一级目录,那么makefile是无法知道main.c的存在,所以这里编写依赖关系的时候,我们就得注意要带相对路径,然后就是依赖方法,这里注意gcc编译的时候,后面得添加-c选项,也就是告诉编译器只编译生成.o文件,而我们的main.c中有#include"mylib.h"语句也就是引用了mylib.h头文件,那么此时编译器会去寻找mylib.h,那么编译器要么就是从我们上文所说的那几个默认路径下去寻找到,要么就是当前main.c所处的同级目录下寻找,但是main.c和mylib.h不在同一级,所以我们需要加-I选项后面指定引用头文件所处的目录,然后编译器会从该目录中找到mylib.h
mylib.o:project/$(SRC_DIR)/mylib.cgcc -c $^ -Iproject/$(INC_DIR) -o $@
那么有了main.o之后,下一步则是构建linmylib.a,libmylib则是.o文件的集合,那么它则是依赖于mylib.c编译形成的mylib.o,我们将.o文件给打包成静态库文件的指令则是:ar rcs
其中ar指令则是将依赖关系后面的.o文件打包成一个库,而rcs选项每一个选项的作用则是:
r(replace)
:替换库中已有的同名模块c(create)
:若库不存在则创建s(index)
:生成符号表加速链接
$(LIB):mylib.oar rcs $@ $^
然后接着再是构建mylib.o,那么mylib.o则依赖mylib.c,那么我们编写依赖关系的时候,同样要加上路径,因为mylib.c与makefile不处于同一级目录下,我们得让makefile知道我们mylib.c的存在,而对于依赖方法,那么由于mylib.c也引用了mylib.h,所以gcc编译时和上面一样需要加-I选项
mylib.o:project/$(SRC_DIR)/mylib.cgcc -c $^ -Iproject/$(INC_DIR) -o $@
那么有了最终的libmylib.a以及main.o,那么下一步就是将其链接形成myprogram,而上文我们知道连接器只能在系统保存的默认路径下以及当前所处的目录寻找静态库,那么我们就需要告诉它我们链接的静态库所处的目录,以及静态库的名称,也就是-L选项后面指定路径,-l指定名称,而名称则注意是去掉lib前缀以及.a后缀的名称
有了可执行文件以及静态库,那么我们最后在makefile中定义一个伪目标,创建一个output目录并且将libmylib.o等文件给打包到output目录中
$(OUT_DIR): $(LIB) main.o $(EXE) project/$(INC_DIR)mkdir -p $(OUT_DIR) mv $(LIB) $(OUT_DIR)/ mv main.o $(OUT_DIR)/cp $(EXE) $(OUT_DIR)/ cp -r project/$(INC_DIR) $(OUT_DIR)
完整makefile:
LIB=libmylib.a
SRC_DIR=src
INC_DIR=include
EXE=myprogrma
OUT_DIR=output$(EXE):$(LIB) main.ogcc main.o -L. -lmylib -o $@
$(LIB):mylib.oar rcs $@ $^
mylib.o:project/$(SRC_DIR)/mylib.cgcc -c $^ -Iproject/$(INC_DIR) -o $@
main.o:project/main.cgcc -c $^ -Iproject/$(INC_DIR)
.PHONY:clean
clean:rm -rf $(OUT_DIR)
$(OUT_DIR): $(LIB) main.o $(EXE) project/$(INC_DIR)mkdir -p $(OUT_DIR) mv $(LIB) $(OUT_DIR)/ mv main.o $(OUT_DIR)/cp $(EXE) $(OUT_DIR)/ cp -r project/$(INC_DIR) $(OUT_DIR)
Linux运行截图:
补充:
那么我们实现静态库的核心并不是如何编写得到一个静态库,而是编译器如何找到静态库,那么我们这里让编译器找到静态库有几种方式,那么其中第一种方式便是上文编译时带选项告诉给编译器静态库所在位置,而我们知道编译器还会从默认路径下user/lib中搜索,所以你可以选择将libmylib.a拷贝到该路径下
还有一种方式则是在该user/lib下定义建立一个软链接,文件名为libmylib.a,那么内容就是我们编写的静态库的路径,那么编译器找到后能够跳转到找到我们自定义的静态库位置
动态库
动态库是什么
而所谓的动态库,其实上文说了,本质上它的构成和静态库其实是一样的,但是动态库的链接方式和静态库不一样,那么在Linux上,动态库的命名标准是libXXX.so,也就是自己定义的动态库必须有lib前缀以及.so后缀
其中这里对于动态库的链接,那么这里关键要和静态库进行区分的是,它是在运行时进行链接的,而不是编译时进行链接的,因为程序调用了动态库的库函数,但是此时该可执行程序并没有相应的库函数的定义,而需要的库函数的定义是在系统其他位置保存着的,所以为了寻找到库函数的定义,那么此时就是系统的动态链接器来寻找,那么它会从几个默认路径下去寻找,其中就包括环境变量LD_LIBRARY_PATH,然后找到库中对应调用的函数的定义所在的库文件,然后将库文件给加载到内存中,而具体怎么找到对应的库文件,是因为我们在编译阶段会生成一个符号表,上文说过,符号表会记录哪些未解析的函数是外部引用也就是需要动态链接的,那么此时链接器会拿着这些函数的声明与动态库文件的导出符号表一一匹配,那么导出符号表就记录了其函数定义所在的地址,然后将其加载到内存,这也就是为什么动态库文件具有可执行权限的原因
动态库的优点就是生成的可执行文件体积小,而缺点则是如果动态库缺失,那么程序就无法正常执行了
动态库怎么实现
那么我们这里的源文件以及头文件所处的目录结构以及对应的头文件以及源文件的内容和上文静态库是一样的,只不过这里将源文件打包到动态库,
而这里编译源文件的时候,要加-fPIC选项,那么该选项是告诉编译器生成一个位置无关码,位置无关码允许代码在内存任意位置加载和秩序,是该动态库加载到内存所必须的
gcc -c fPIC $^ -o $@
其次就是打包成动态库的时候,需要加-shared选项,告诉链接器生成一个共享库
gcc $^ -shared -o $@
makefile完整实现:
LIB=libmylib.so
INC_DIR=include
SRC_DIR=src
EXE=myprogma
OUT_DIR=output$(EXE):main.o $(LIB)gcc main.o -L. -lmylib -o $@
$(LIB):mylib.ogcc $^ -shared -o $@
mylib.o:project/src/mylib.cgcc -c -fPIC $^ -Iproject/$(INC_DIR) -o $@
main.o:project/main.cgcc -c $^ -Iproject/$(INC_DIR) -o $@
.PHONY:clean
clean:rm -rf main.o mylib.o $(EXE) $(OUT_DIR)
output:$(EXE) main.o $(LIB)mkdir -p $(OUT_DIR)cp $(EXE) $(OUT_DIR)/cp -r project/$(INC_DIR) $(OUT_DIR)/mv $(LIB) $(OUT_DIR)/cp main.o $(OUT_DIR)/
Linux运行截图:
但是我们在运行的时候,发现动态连接器找不到对应的动态库,那么此时我们就要确保系统找到动态库,那么我们就需要将我们动态库所处的目录添加到环境变量也就是LD_LISARBRY当中,那么这样就可以成功运行了
结语
那么这就是本篇关于动静态库的全面剖析,那么我的下一篇文章便会进入一个全新的章节,也就是进程地址空间,那么希望读者下来可以自己去实现一个自己的动静态库,那么我会持续更新,希望你多多关注,如果本文有帮组到你,还请三连加关注,你的支持,就是我创作的最大的动力!
相关文章:
【Linux内核系列】:动静态库详解
🔥 本文专栏:Linux 🌸作者主页:努力努力再努力wz 💪 今日博客励志语录: 有些鸟儿是注定是关不住的,因为它们的每一片羽翼都沾满了自由的光辉 ★★★ 本文前置知识: 编译与链接的过程…...
【IROS 2025】CMU提出路径规划器PIPE:机器人探索效率提升14.6%,地图准确率提高9.3%!
在自主机器人探索未知环境的研究中,如何高效地规划路径、最大化信息获取,一直是一个核心问题。传统的方法往往仅在离散的路径点上计算信息增益,而缺乏对整个路径信息获取的综合考量,从而可能导致探索低效甚至错误的规划决策。近日…...
《笔记》Android 获取第三方应用及查看应用信息、apk大小、缓存、存储,以及第三方清除缓存
获取应用相关信息: PS:manifest标签中设置以下属性表示系统应用 android:process"system" android:sharedUserId"android.uid.system" //获取所有应用(非系统apk,有些应用获取不到) List<ApplicationInf…...
npm 安装 pnpm 的详细步骤及注意事项
一、安装步骤 1.全局安装 pnpm npm install -g pnpm2.验证安装 pnpm -v输出版本号即表示安装成功。 二、升级 pnpm 若已安装旧版本,可通过以下命令升级: npm install -g pnpmlatest三、配置镜像加速 设置淘宝镜像 pnpm config set registry http…...
大白话详细解读React框架的diffing算法
1. Diffing 算法是什么? Diffing 算法是 React 用来比较虚拟 DOM(Virtual DOM)树的一种算法。它的作用是找出前后两次渲染之间的差异(diff),然后只更新这些差异部分,而不是重新渲染整个页面。 …...
【架构】单体架构 vs 微服务架构:如何选择最适合你的技术方案?
文章目录 ⭐前言⭐一、架构设计的本质差异🌟1、代码与数据结构的对比🌟2、技术栈的灵活性 ⭐二、开发与维护的成本博弈🌟1、开发效率的阶段性差异🌟2、维护成本的隐形陷阱 ⭐三、部署与扩展的实战策略🌟1、部署模式的本…...
面试redis常被问到的面试题含答案
什么是Redis?它的特点是什么? Redis是一个开源的内存数据库,用于存储数据并支持多种数据结构(如字符串、哈希、列表、集合、有序集合等)。其特点包括高性能、支持持久化、数据结构丰富、原子性操作、支持事务等。 Red…...
Asp.net Core API 本地化
本文是一个demo,演示了如何根据用户接口查询字段(正常放header中),设置当前culture,并获取当前culture的key value给用户提示 创建Resources文件夹,添加以下三个文件 其中ExceptionUnuse 是一个空的类,供IStringLocalizer使用&a…...
使用Java实现Oracle表结构转换为PostgreSQL的示例方案(AI)
核心代码 import java.sql.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;public class OracleToPGConverter {// 类型映射表private static final Map<String, String> TYPE_MAPPING new HashMap<>()…...
win32汇编环境,网络编程入门之八
;在上一教程里,我们学习了简单的处理服务器返回的数据 ;在这一教程里,我们了解一下,当连接上网站后,应该发送什么数据过去的问题 ;这里有个简单的方式学习,以下是一个示例 ;我们上网的时候可以用谷歌浏览器,…...
Java EE 进阶:MyBatis
MyBatis是一个优秀的持久化框架,用于简化JDBC的开发。 持久层就是持久化访问的层,就是数据访问层(Dao),用于访问数据库的。 MyBatis使用的准备工作 创建项目,导入mybatis的启动依赖,mysql的驱…...
Linux驱动开发基础(can)
目录 1.can的介绍 2.can的硬件连接 2.1 CPU自带can控制器 2.2 CPU没有can控制器 3.电气属性 4.can的特点 5.can协议 5.1 can的种类 5.2 数据帧 5.2.1 标准数据帧格式 5.3.1 扩展数据帧格式 5.3 遥控帧 5.4 错误帧 5.5 过载帧 5.6 帧间隔 5.7 位填充 5.8 位时…...
Linux 命令行整理(完善中)
文件类 查看文件类 cat 用于连接文件并打印到标准输出设备上,可用于查看文件内容.(短文件) use:cat example.txtmore 分页的形式显示文件内容,适合查看较长的文件(长) use: more example.txtless 也是分页查看文件内容ÿ…...
回调方法传值汇总
<template v-slot"scope"><el-switch v-model"scope.row.open" change"(p1) > changeOpen(p1, scope.row)"></el-switch></template>公域流量 多选 selection-change“val > multipleSelection val”...
分享一个精灵图生成和拆分的实现
概述 精灵图(Sprite)是一种将多个小图像合并到单个图像文件中的技术,广泛应用于网页开发、游戏开发和UI设计中。在MapboxGL中,跟之配套的还有一个json文件用来记录图标的大小和位置。本文分享基于Node和sharp库实现精灵图的合并与…...
python中的min函数的key的用法 - abs绝对值
前言 继续上一章节提及的 Python 中 min() 函数的用法,包括其基本语法、处理列表、接收多个参数 这个章节将补充一些新的知识点例如: min函数中key的另一种用法abs绝对值 min(iterable, *iterables, keyNone, defaultNone) 知识点 key 参数 key 是一个可选参数…...
我开发的PDF转WORD免费工具
ZhouShengHuan 欢迎小伙伴使用~...
kubernetes高级实战
一、模拟企业环境进行一个实战部署 [rootmaster node]# kubectl apply -f pod-tomcat.yaml pod/tomcat-test created [rootmaster node]# kubectl get pods NAME READY STATUS RESTARTS AGE tomcat-test 2/2 Running 0 2s [rootmaster node]…...
IntelliJ 配置文件plugin.xml
在 IntelliJ IDEA 插件开发中,plugin.xml 是插件的配置文件,它包含了关于插件的所有基本信息、扩展点、依赖关系等。该文件使用 XML 格式进行定义。以下是 plugin.xml 中常见的元素及其用途: <idea-plugin><!-- 插件的基本信息 --&…...
《心理学与生活》2025最新网课答案
《心理学与生活》2025最新网课答案 文章目录 《心理学与生活》2025最新网课答案发展与教育单元测试情绪与情感单元测验人格与动机单元测试感知与记忆单元测试文化与社会单元测试 发展与教育单元测试 题数 20 棉花糖实验中哪些小孩长大后的表现更好()。 …...
11 python 数据容器-字符串
一、什么是数据容器 举个例子,一个办公室里有一群牛马,他们都有自己的名字,如果没有容器的概念,那么我们用变量来存放他们的名字,比如: name1 "翠花" name2 "玛丽" name3 "二…...
2025.3.20总结
阅读:《时间贫穷》第二章,里面讲到,运动,多行善事,体验自然,都会增强自我效能感,是对抗时间焦虑的强有力的方式。 花时间运动是值得的,公司每周三都是运动周,把运动视作…...
鸿蒙NEXT开发问题大全(不断更新中.....)
目录 问题1:鸿蒙NEXT获取华为手机的udid 问题2:[Fail]ExecuteCommand need connect-key? 问题3:测试时如何安装app包 问题1:鸿蒙NEXT开发获取华为手机的udid hdc -t "设备的序列号" shell bm get --udid 问题2&…...
【北京迅为】iTOP-RK3568开发板OpenHarmony系统南向驱动开发UART接口运作机制
瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工…...
大模型在冠心病风险预测及临床方案制定中的应用研究
目录 一、引言 1.1 研究背景与目的 1.2 国内外研究现状 1.3 研究方法与创新点 二、大模型预测冠心病风险原理与方法 2.1 数据收集与预处理 2.1.1 数据来源 2.1.2 数据清洗与整理 2.2 特征工程 2.2.1 特征提取 2.2.2 特征选择与优化 2.3 模型选择与训练 2.3.1 常用…...
【从零开始:如何用Vue3打造响应式个人博客网站】
前言 在前端开发领域,Vue.js 是一个非常流行且强大的框架。本文将详细介绍如何使用 Vue3 构建一个完整的响应式个人博客网站。无论你是初学者还是有一定经验的开发者,本文都将为你提供详细的步骤和代码示例。 1. 环境搭建 首先,确保你已经安…...
【vulhub/wordpress靶场】------获取webshell
1.进入靶场环境: 输入:cd / vulhub / wordpress / pwnscriptum 修改版本号: vim docker-compose.yml version: 3 保存退出 开启靶场环境: docker - compose up - d 开启成功,docker ps查看端口 靶场环境80…...
ngx_http_conf_ctx_t
定义在 src/http/ngx_http_config.h typedef struct {void **main_conf;void **srv_conf;void **loc_conf; } ngx_http_conf_ctx_t; ngx_http_conf_ctx_t 是 Nginx 中用于管理 HTTP 配置上下文的核心结构体,其设计体现了 Nginx 多级配置&…...
大模型+知识图谱:赋能知识智能新升级
在大模型(Large Language Model, LLM)飞速发展的今天,如何把传统行业中沉淀多年的大量结构化与非结构化数据真正“用起来”,正成为推动智能化转型的关键一步。 找得到,看得懂,为何很难? 以制造…...
python学智能算法(八)|决策树
【1】引言 前序学习进程中,已经对KNN邻近算法有了探索,相关文章链接为: python学智能算法(七)|KNN邻近算法-CSDN博客 但KNN邻近算法有一个特点是:它在分类的时候,不能知晓每个类别内事物的具…...
压力测试实战指南:JMeter 5.x深度解析与QPS/TPS性能优化
一、压力测试基础概念 1.1 什么是压力测试? 定义:模拟极端负载场景验证系统性能极限 目的:发现性能瓶颈、评估系统可靠性、验证容错能力 常见类型:负载测试、压力测试、稳定性测试、峰值测试 1.2 核心性能指标解析 1.2.1 QP…...
鸿蒙NEXT项目实战-百得知识库04
代码仓地址,大家记得点个star IbestKnowTeach: 百得知识库基于鸿蒙NEXT稳定版实现的一款企业级开发项目案例。 本案例涉及到多个鸿蒙相关技术知识点: 1、布局 2、配置文件 3、组件的封装和使用 4、路由的使用 5、请求响应拦截器的封装 6、位置服务 7、三…...
Spring Boot Actuator 自定义健康检查(附Demo)
目录 前言1. Demo2. 拓展 前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF Spring Boot 的 actuator 提供了应用监控的功能,其中健康检查(Health Check)是一个重要的部分&…...
Flutter小白零基础入门到高级项目实战全集
Flutter零基础入门到高级项目实战全集内容如下: Dart入门基础教程16讲、Null safety 、late 关键字、空类型声明符?、非空断言!、required 、Flutter入门基础、Flutter瀑布流布局、Flutter动画、Flutter异步流、GlobalKey 、Flutter国际化、…...
TCP 协议
文章目录 TCP 协议简介数据包格式TCP的特性连接机制确认与重传缓冲机制全双工通信流量控制差错控制拥塞控制 端口号三次握手数据传输四次挥手抓包参考 本文为笔者学习以太网对网上资料归纳整理所做的笔记,文末均附有参考链接,如侵权,请联系删…...
NO.51十六届蓝桥杯备战|堆算法题|第k小|除2|最小函数值|序列合并|舞蹈课(C++)
P3378 【模板】堆 - 洛谷 #include <bits/stdc.h> using namespace std;const int N 1e6 10; int n; int heap[N];void up(int child) {int parent child / 2;while (parent > 1 && heap[child] < heap[parent]){swap(heap[child], heap[parent]);chil…...
【QA】观察者模式在QT有哪些应用?
1. 信号与槽机制 Qt的**信号与槽(Signals & Slots)**是观察者模式的典型实现,通过元对象系统(Meta-Object System)实现松耦合通信。 核心特点: 类型安全:编译时检查参数匹配跨线程支持&…...
coze ai assistant Task5
没想到coze的组队学习这么快就过去了,我也从一个不懂coze的小白变成了一个能简单尝试小程序的懵懂小白。虽然几次学习并不能掌握很多的技能,但也让我知道coze的无限可能,组队结束后我会继续努力学习,做更多使自己偷懒的小工具~ 需…...
MATLAB神经网络优化1000个案例算法汇总
【2025最新版】MATLAB神经网络优化1000个案例算法汇总(长期更新版) 本文聚焦神经网络、优化算法,神经网络改进,优化算法改进,优化算法优化神经网络权重、超参数等,现在只需订阅即可拥有,简直是人工智能初学者的天堂。…...
Android Coil3 Fetcher preload批量Bitmap拼接扁平宽图,Kotlin
Android Coil3 Fetcher preload批量Bitmap拼接扁平宽图,Kotlin 在这一篇文章基础上改进: Android Coil3阶梯preload批量Bitmap拼接扁平宽图,Kotlin-CSDN博客文章浏览阅读854次,点赞18次,收藏5次。遗留问题,…...
Ubuntu 24 常用命令方法
文章目录 环境说明1、账号管理1.1、启用 root 2、包管理工具 apt & dpkg2.1、apt 简介 & 阿里源配置2.2、dpkg 简介2.3、apt 和 dpkg 两者之间的关系2.4、常用命令 3、启用 ssh 服务4、防火墙5、开启远程登录6、关闭交换分区7、build-essential(编译和开发软…...
uniapp自身bug | uniapp+vue3打包后 index.html无法直接运行
前提: 已经修改了基础路径 打开打包文件,双击运行index.html报错,无法访问页面 uniappvue2项目是可以正常运行的 vue3修改publicPath: ./后,也是可以正常访问打包文件中的index.html 点进控制台提供的链接:https:/…...
go~协程阻塞分析
错误示例 type chanData struct {result stringerror error }func Biz1() {t := time.NewTimer(time.Second * 10)ctx := context.Background()ch := make(chan chanData)go doChan(ctx, ch)fmt.Println("Biz1 begin")for {select {case <-t.C:fmt.Println(&quo…...
【机器学习】什么是逻辑回归
什么是逻辑回归 一、摘要二、逻辑回归算法简介三、sigmoid函数实现四、思考题 一、摘要 本文主要讲述了逻辑回归算法的基本原理和应用。首先介绍了逻辑回归在机器学习领域的重要地位,然后解释了其名称的由来和如何利用样本特征和概率之间的关系进行分类。通过与线性…...
postman小白教程(从入门到实战,详细教学)
目录 1. postman介绍 2. 下载地址 3. 安装流程 4. 注册postman账号 ① 打开postman,点击【创建账号】或【登录】,会跳转到浏览器 ② 若已有账号可以直接登录;若无账号,则创建新账号 ③ 若登录成功会弹出提示框,…...
4.1-4 SadTalker数字人 语音和嘴唇对应的方案
前言: SadTalker是一个强大的数字人相关的RA/SD插件。它本身是一个非常独立的产品。你只需要提供一段视频,一段文字,简单的配置,在RA/SD中简单的生成即可。 视频中人物的嘴唇很好的应对了你要发声的文字内容。效果很赞。仔细学习…...
Linux CentOS7 安装 ffmpeg教程
官网:FFmpeg 操作 先用uname -a 查看内核版本,如果是 3.2.0或者以上就可以按照此办法来安装 cd /tmp wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz# 2. 解压 tar xvf ffmpeg-release-amd64-static.tar.xz# 3. 将…...
docker desktop 集成WSL Ubuntu22.04
Windows docker desktop 设置WSL ubuntu 22.04启用与其他发行版的集成 Windows docker desktop 安装参考 wsl ubuntu 22.04 查看我宿主机的docker desktop 容器全部的信息 wsl -d Ubuntu-22.04 -u root...
【AI】AI编程助手:Cursor、Codeium、GitHub Copilot、Roo Cline、Tabnine
文章目录 一、基本特性对比二、收费标准三、私有部署能力1、Tabnine2、Roo Code 三、代码补全与自然语言生成代码四、安装独立的IDE安装插件安装 五、基本使用(一)Cursor(二)GitHub Copilot1、获取代码建议2.聊天1)上下…...
Android audio(8)-native音频服务的启动与协作(audiopolicyservice和audioflinger)
音频策略的构建 1、概述 2、AudiopolicyService 2.1 任务 2.2 启动流程 2.2.1 加载audio_policy.conf(xml)配置文件 2.2.2 初始化各种音频流对应的音量调节点 2.2.3 加载audio policy硬件抽象库 2.2.4设置输出设备 ps:audiopatch流程简介 2.2.5打开输出设…...