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

C缺陷与陷阱 — 8 编译与链接

目录

1 程序的编译过程

2 动态链接的优缺点

2.1 动态链接的优点

2.2 动态链接的缺点

2.3 只使用动态链接

3 函数库链接的5个特殊秘密

4 警惕Interpositioning

5 产生链接器报告文件


1 程序的编译过程

程序的编译过程是将源代码转换成计算机可以执行的机器代码的过程。这个过程通常包括以下几个主要步骤:

(1)预处理(Preprocessing预处理是编译过程的起始步骤,主要针对源代码文件中的预处理指令进行相应处理。

  • 宏定义展开(#define):通过#define指令定义宏,预处理时会按照定义规则对代码里相应的宏进行文本替换,比如定义#define PI 3.14,代码中出现PI的地方就会被替换成3.14。
  • 条件编译指令(#ifdef、#ifndef、#endif 等):条件编译指令可依据是否定义了特定宏等条件,来决定代码段是否参与后续编译。
  • 包含头文件(#include:预处理器会把指定头文件的全部内容插入到源代码中相应的位置。例如,#include <stdio.h>会将标准输入输出头文件里的内容(像printf、scanf等函数的声明等)添加进来。

(2)编译(Compilation):将预处理后的源代码转换为中间代码,并进行优化以及最终生成目标代码的过程,涉及多个子环节。

  • 词法分析:编译器会把预处理后的源代码当作字符流,将其拆解成一个个单词(tokens),这些单词涵盖了编程语言里的关键字(如 C 语言中的int、if、for等)、标识符(变量名、函数名等)、常量(整数常量、浮点数常量、字符常量等)、运算符(+、-、*、/等)以及界符(;、{、}等)。例如对于代码int num = 10;,词法分析器能准确分解出 “int”(关键字)、“num”(标识符)、“=”(运算符)、“10”(常量)和 “;”(界符),为后续分析提供基础元素。
  • 语法分析:基于词法分析得到的单词,编译器依据编程语言既定的语法规则构建语法树,以树形结构清晰呈现程序的语法构成以及语句、表达式之间的层次关系。比如针对if语句if (condition) { statement; },语法树会将if作为根节点,其下细分出条件表达式condition节点以及语句块statement节点。一旦代码存在语法错误,像括号缺失或者关键字拼写有误等情况,语法分析阶段就能检测出来。
  • 语义分析:主要检查程序语义的正确性,包含检查变量是否正确定义与使用、类型是否匹配等关键方面。例如在表达式int a = 3.14;中,语义分析环节会察觉到将双精度浮点数赋值给整型变量属于类型不匹配的错误;同时也会处理变量的作用域问题,确保变量仅在其定义的有效范围内被正确访问,例如函数内部定义的局部变量不能在函数外部随意调用。
  • 中间代码生成:部分编译器会生成中间代码,它处于源语言与目标机器语言之间,具备平台无关性优势,常见形式有三地址码等。例如对于表达式a = b + c,可能生成类似t1 = b + c; a = t1的三地址码形式,这种中间表示形式利于后续进一步的优化以及适配不同目标机器的代码生成工作。
  • 代码优化:编译器会对生成的中间代码实施优化操作,旨在提升程序的执行效率,优化手段多种多样。比如常量折叠,像int a = 2 + 3;可直接优化为int a = 5;,减少不必要的运算;死代码消除,即去除那些永远不会被执行的代码,避免占用资源;循环展开,通过将循环体展开一定次数来降低循环控制方面的开销等,通过这些优化策略让程序在执行时间和存储空间利用上更为高效。
  • 目标代码生成:这是编译阶段的收尾环节,会把经过优化的中间代码(若有)或者直接把处理后的代码转换为目标机器的语言,这种目标代码可能是汇编语言形式,也有可能直接就是机器代码(二进制形式),具体取决于编译器的设计以及编译的配置。

(3)汇编(Assembly):汇编器(Assembler)将汇编语言代码转换成机器代码。汇编语言是一种低级语言,它更接近于机器代码,但仍然包含一些助记符,使得程序员更容易理解和编写。

(4)链接(Linking):链接过程旨在将编译生成的多个目标文件(通常以.o(在 Linux 等系统下)或.obj(在 Windows 系统下)为扩展名)与各类库文件以及其他相关目标文件进行合并整合,最终生成一个单一的可执行文件(像.exe(Windows 系统)或.out(Linux 等系统)文件)。

  • 符号解析:目标文件中包含诸多符号,例如函数名、全局变量名等,链接器的关键任务之一就是确定这些符号的具体定义位置。比如一个源文件中调用了另一个源文件里定义的函数int add(int a, int b),在链接时,链接器必须精准找到该函数实现代码所在的目标文件,若无法找到某个符号的定义,就会出现如 “undefined reference to 'add'” 这类链接错误提示。
  • 重定位:目标文件中的代码与数据部分往往包含一些相对地址或者虚拟地址,在链接阶段,需要依照最终可执行文件的整体布局对这些地址进行相应调整。例如,目标文件中某个函数调用指令原本采用相对地址来指向被调用函数,当链接器把多个目标文件组合到一起时,就需要重新计算这些相对地址,以保障函数调用能够准确无误地跳转到被调用函数的实际内存位置,确保程序执行的正确性。
  • 库链接:程序在开发过程中通常会借助一些库来实现额外的功能,像标准 C 库、数学库等,链接器要把这些库文件与目标文件妥善链接起来。库分为静态库和动态库两种类型,静态库是多个目标文件的集合,链接时,链接器会把程序实际使用的静态库中目标文件的代码和数据全部复制到最终可执行文件里。动态库链接时不会把库文件全部代码复制到可执行文件中,而是在程序运行需调用其函数时,由操作系统加载动态库并完成相应函数调用操作。

(5)加载(Loading):加载器(Loader)负责将可执行文件加载到内存中,进而启动程序的执行流程。

2 动态链接的优缺点

2.1 动态链接的优点

动态链接是一种更为现代的方法,能够更加有效地利用磁盘空间,动态链接只需要处理对动态库的引用关系,不需要像静态链接那样将库的全部代码合并到可执行文件中,因此在编译和链接阶段时间也会缩短。尽管单个可执行文件约启动速度稍受影响,但动态链接可以从两个方面提高性能:

(1)动态链接可执行文件比功能相同的静态链接可执行文件的体积小,相应的会节省磁盘空间和虚拟内存。静态链接在生成可执行文件时,会把程序所用到的函数库(比如标准 C 库、数学库等)中相关目标文件的代码和数据全部复制到可执行文件里面,即便它可能只调用了库中的少数几个函数,而动态链接则不同,动态链接的可执行文件中只是包含了对相应动态库中函数和变量等的引用信息,真正的函数库代码并不嵌入到可执行文件里。

(2)当多个可执行文件都动态链接到同一个特定函数库时,在运行期间,操作系统只会把这个函数库加载到内存中一次,形成一个单独的拷贝。例如,在 Linux 系统下,多个应用程序都动态链接了libc.so(C 标准库对应的动态库),那么在内存中只会存在一份libc.so的实例。操作系统内核通过内存映射机制来实现共享,它会将这份已加载到内存中的函数库映射到每个需要使用它的进程的虚拟地址空间中。各个进程虽然感觉像是自己独占了这个函数库,但实际上它们共享的是同一份物理内存中的代码和数据,这样就避免了重复加载相同的函数库内容到内存里。如果可执行文件是静态链接的,每个文件都将拥有一份函数库的拷贝,显然极为浪费。

动态链接使得函数库的版本升级更为容易。新的函数库可以随时发布,只要安装到系统中,旧的程序就能够自动获得新版本函数库的优点而无需重新链接。

2.2 动态链接的缺点

动态链接是一种“just-in-time(JIT)”链接,这意味着程序在运行时必须能够找到它们所需要的函数库。链接器通过把库文件名或路径名植入可执行文件中来做到这一点。这意味着,函数库的路径不能随意移动。如果把程序链接到/user/ib/libthread.so库,那么就不能把该函数库移动到其他的目录,除非在链接器中进行特别说明。否则,当程序调用该函数库的函数时,就会在运行时导致失败,给出这样一条错误信息:

ld.so.1:main:fatal:libthread.so:can't open file:errno 2

当在一台机器上编译完程序后,把它拿到另一台不同的机器上运行时,也可能出现这种

情况。执行程序的机器必须具有所有该程序需要链接的函数库,而且这些函数库必须位于在链接器中所说明的目录。对于标准系统函数库而言,这并不成问题。

2.3 只使用动态链接

动态链接现在是运行System V release4UNIX的计算机所采用的缺省设置。从作用上

看,静态链接现已过时,只能静静躺在一边睡大觉。

使用静态链接的最大危险在于将来版本的操作系统可能与可执行文件所绑定的系统函数库不兼容。如果应用程序静态链接于版本N的操作系统中,当把程序运行于版本N+1的操作系统上时,它可能会立即崩溃,也可能出现一个不明显的错误。我们无法保证早期版本的系统函数库能够在后期版本的系统上正确地运行。事实上,反过来考虑倒还比较保险一点。但是,如果应用程序动态链接到版本N的系统函数库,当它运行于版本N+1的操作系统上时,它就会正确选取N+1版本的系统函数库。

相反,静态链接的应用程序不得不针对每个新版本的操作系统进行重新生成以保证能够运行。而且,有些函数库(扣libaio.so,libdl.so,libsys..so,libsolv.so以及librpcsvc.so等)只能以动态链接的形式使用。如果在应用程序中使用了这些函数库中的任何一个,你的程序就必须使用动态链接。最好的策略就是所有的应用程序都使用动态链接,这就可以避免可能产生的问题。

3 函数库链接的5个特殊秘密

当使用函数库时,需要掌握5个基本的、不明显的约定。绝大多数C语言书籍或手册对此并没有作出清楚的解释。

(1)动态库文件的扩展名是“.so”,而静态库文件的扩展名是“.a

按照约定,所有动态库的文件名的形式是libname.so。这样,线程函数库便被称作libthread.so。静态库的文件名形式是libname.a,共享archive的文件名形式是libname.sa。共享archive只是一种过渡形式,帮助人们从静态库转变到动态库,现在已过时。

(2)通过-lthread选项,告诉编译链接到libthread.so

传给C编译器的命令行参数里并没有提到函数库的完整路径名,甚至没有提到在函数库目录中该文件的完整名字!函数库名字的呈现形式是把 “lib” 部分和文件的扩展名去掉,然后在前面添加一个 “l”。例如,对于名为 libthread.so 的函数库,在命令行中就是通过 -lthread 选项来告知编译器去链接它。

gcc -o thread_demo thread_demo.c -lthread

(3)编译器期望在确定的目录找到库

这里,你可能会疑惑,编译器是怎么知道该往什么目录寻找函数库呢?就像存在一种特殊的规则用于查找头文件一样,编译器也自有办法来寻找函数库。它查看一些特殊的位置,如在/usr/ib中查找函数库,例如线程库位于usr/Iib/libthread.so。

编译器选项-Lpathname告诉链接器一些其他的目录,如果命令中加入了-l选项,链接器就往这些目录查找函数库。系统中存在几个环境变量,LD LIBRARY_PATH和

LD_RUN_PATH,也是用于提供这类信息。出于安全性、性能和创建/运行独立性方面的考虑,使用环境变量的做法现在己经不提倡。一般还是在链接时使用-Lpathname和-Rpathname选项。

(4)观察头文件,确认所使用的函数库

你有可能遇见的另一个关键问题是“我怎么知道必须链接到哪些函数库?如果观察程序中的源代码,就会发现自己调用了一些自己不曾实现的函数。例如,如果程序跟三角有关,可能会调用像sin()和cos()这样的函数,它们可以在math函数库中找到。

一个很好的建议就是可以观察程序所使片的#include指令。在程序中所包舍的每个头文件都可能代表一个必须链接的库,但需要注意头文件的名字通常并不与它所对应的函数库名相似。函数库链接所存在的另一个不一致性就是函数库所包含的某个函数的原型可能与其他头文件中所声明的函数的原型一样。

(5)与提取动态库中的符号相比,静态库中的符号提取的方法限制更严

最后,在动态链接和静态链接的链接语义上还存在一个额外的大区别,它经常会迷惑不够仔细的用户。

假设我们有一个简单的 main.c 文件,里面调用了一些来自标准 C 库的函数(比如 printf 函数,其所在的库在动态链接时会被自动处理),使用 gcc 编译器进行动态链接编译生成可执行文件的命令示例如下:

gcc main.c -o dynamic_executable

这里,-o 选项指定了输出的可执行文件名是 dynamic_executable。在这个过程中,像 printf 这类库符号所在的动态库(例如 libc.so 等)会在运行时被加载到程序的虚拟地址空间,使得程序可以找到并执行相应的函数,并且多个链接在一起的文件都可以访问到这些动态库中的符号。

同样针对上述 main.c 文件进行静态链接,并且假设有一个自定义的静态库 mylib.a,同时假设 main.c 中调用了 mylib.a 里定义的函数以及标准 C 库中的函数(比如 printf),按照正确顺序进行静态链接编译生成可执行文件的命令示例如下:

gcc main.c mylib.a -o static_executable

这里必须保证先写 main.c ,再写 mylib.a ,因为静态链接时符号是从左到右按顺序解析的,如果写成:

gcc mylib.a main.c -o static_executable

可能就会出现问题,因为在处理 mylib.a 这个静态库时,链接器一开始还没遇到 main.c 里对 mylib.a 中符号的未定义引用(也就是还不知道需要从 mylib.a 里找哪些符号),那么就可能不会正确地从 mylib.a 中提取对应的符号,导致后续链接 main.c 时出现符号未定义等错误。

如果在自己的代码之前引入静态库,又会带来另一个问题。因为此时尚未出现未定义的符号,所以它不会从函数库中提取任何符号。接着,当目标文件被链接器处理时,它所有的对函数库的引用都将是未实现的!

例如,像 “cc -lm main.c” 这样进行静态链接(math 库常以静态链接的 archive 形式存在用于提高运行时性能),若程序使用了如 sin 等数学函数,会得到 “Undefined first referenced symbol in file sin main.o ld:fatal:Symbol referencing errors.No output written to a.out” 这样的错误信息。

为从 math 库中提取所需符号,需要写成 “cc main.c -lm” 这种形式,让文件先包含未解析的引用。个人都习惯了通用的命令形式<命令><选项><文件>,所以让链接器采用<命令><文件><选项>这样的约定是很容易引起混淆。

4 警惕Interpositioning

Interpositioning 是一种通过编写与函数同名的函数来取代库函数行为的技术。可以在特定程序中拦截库函数的调用,以便检查参数、返回值或跟踪程序的执行流程,有助于快速定位问题。在某些情况下,可以通过优化同名的用户函数来提高特定操作的执行效率。

使用Interpositioning需要格外小心。很容易发生自己代码中某个符号的定义取代函数库中的相同符号的意外。这意味着不仅自己对该库函数的调用会被自己版本的函数调用所取代,而且所有调用该库函数的系统调用也会被用户函数取代。例如,假设程序中使用了一个库函数 printf 进行输出,而程序员不小心编写了一个同名的 printf 函数。在这种情况下,程序中所有原本应该调用库函数 printf 的地方都会调用用户自定义的 printf 函数,这可能会导致输出结果与预期不符,甚至可能引发程序错误。

当编译器注意到库函数被另外一个定义覆盖时,它通常不会给出错误信息。这是因为 C 语言遵循“程序员所做的都是对的”的设计哲学,编译器认为这是程序员的意图。这种特性使得在使用 Interpositioning 时,错误很难被及时发现。程序员可能在不经意间使用了这种技术,却没有意识到自己已经覆盖了库函数,从而导致程序出现难以察觉的错误。

由于 Interpositioning 具有较高的风险,只有在确实需要进行调试或提高效率时才考虑使用。对于新手来说,应尽量避免使用这种技术,以免伤害自己。

5 产生链接器报告文件

可以在ld程序中使用“-m”选项,让链接器产生一个报告,里面包括了被Interpose

的符号的说明。通常,带“-m”选项的ld会产生一个内存映射或列表,显示在可执行文件中的什么地方放入了哪些符号。它同时显示了同一个符号的多个实例,通过查看报告的内容,用户可以判断是否发生了Interpositioning。假如你有一个待链接的目标文件叫 main.o,想生成包含符号相关信息的报告,命令可能如下:

ld -m main.o -o output_executable

ld程序中的“-D”选项是随SunOS5.3引入的,日的是提供更好的链接-编辑调试。这个选项允许用户显示链接-编辑过程和所包含的输入文件。如果需要监视从archive中提取对象的过程,这个选项尤其有用,同时可用于显示运行时绑定信息。同样针对 main.o 这个目标文件,想要查看链接编辑过程和涉及的输入文件,命令示例如下:

ld -D main.o -o another_executable

ld是一个复杂的程序,还有很多其他选项和约定未在此处说明。对于绝大多数应用来说,这些说明已经足够了。如需知道更多有关它的知识,下面提供了四条途径,按其复杂程度分列如下:

  • 使用1dd命令,列出可执行文件的动态依赖集。这条命令会告诉你动态链接的程序所需要的函数库。
  • ld程序的-Dhelp选项能提供一些信息,有助于查找链接过程中出现的问题。
  • 查看ld程序的在线文档。

 

相关文章:

C缺陷与陷阱 — 8 编译与链接

目录 1 程序的编译过程 2 动态链接的优缺点 2.1 动态链接的优点 2.2 动态链接的缺点 2.3 只使用动态链接 3 函数库链接的5个特殊秘密 4 警惕Interpositioning 5 产生链接器报告文件 1 程序的编译过程 程序的编译过程是将源代码转换成计算机可以执行的机器代码的过程。…...

知识分享第三十天-力扣343.(整数拆分)

343 整数拆分 给定一个正整数 n&#xff0c;将其拆分为至少两个正整数的和&#xff0c;并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 示例 1: 输入: 2 输出: 1 解释: 2 1 1, 1 1 1。 示例 2: 输入: 10 输出: 36 解释: 10 3 3 4, 3 3 4 36。 说明: 你可…...

Springboot 整合DL4J 打造智能写作助手(文本生成)

项目准备 环境要求: Java 1.8或以上 Maven 或 Gradle&#xff08;用于项目管理&#xff09; Spring Boot框架 DL4J库&#xff08;DeepLearning4J&#xff09; 创建 Spring Boot 项目 使用 Spring Initializr 来生成一个新的 Spring Boot 项目。选择合适的依赖&#xff0c;例如…...

SPL06 基于stm32F103 HAL库驱动(软件模拟IIC)

talk is cheap, show you my code SPL06.c #include "SPL06.h"//*************全局变量*************// Factor_List* b_list; //存储过采样率对应的系数KP&#xff0c;KT COEF_ValueStruct Coefficient { 0 }; //存储校准系数…...

【C#】List求并集、交集、差集

值类型List List<int> intList1 new List<int>() { 1, 2, 3 };List<int> intList2 new List<int>() { 3, 4, 5 };var result intList1.Union(intList2);Console.WriteLine($"并 {string.Join(,,result)}");result intList1.Intersect(in…...

YOLOv8目标检测——详细记录使用ONNX Runtime进行推理部署C++/Python实现

概述 在之前博客中有介绍YOLOv8从环境安装到训练的完整过程&#xff0c;本节主要介绍ONNX Runtime的原理以及使用其进行推理加速&#xff0c;使用Python、C两种编程语言来实现。 https://blog.csdn.net/MariLN/article/details/143924548?spm1001.2014.3001.5501 1. ONNX Ru…...

mfc140u.dll是什么文件?如何解决mfc140u.dll丢失的相关问题

遇到“mfc140u.dll文件丢失”的错误通常影响应用程序的运行&#xff0c;这个问题主要出现在使用Microsoft Visual C环境开发的软件中。mfc140u.dll是一个重要的系统文件&#xff0c;如果它丢失或损坏&#xff0c;会导致相关程序无法启动。本文将简要介绍几种快速有效的方法来恢…...

Redis篇-19--运维篇1-主从复制(主从复制,读写分离,配置实现,实战案例)

1、概述 Redis的主从复制&#xff08;Master-Slave Replication&#xff09;是一种数据冗余机制&#xff0c;它允许将一台Redis服务器的数据复制到其他Redis服务器。在主从复制中&#xff0c;有一台主服务器&#xff08;Master&#xff09;和一个或多个从服务器&#xff08;Sl…...

【Elasticsearch入门到落地】4、Elasticsearch的安装

接上篇《3、es与mysql的概念对比》 上一篇我们学习了Elasticsearch与Mysql的概念与区别。本篇我们来进行Elasticsearch的环境准备及软件安装。 一、环境准备 如果我们没有自己的Linux服务器&#xff0c;且现在正在使用的是Windows操作系统的电脑&#xff0c;那么首先我们需要安…...

计算无人机俯拍图像的地面采样距离(GSD)矩阵

引言 在无人机遥感、测绘和精细农业等领域&#xff0c;地面采样距离&#xff08;Ground Sampling Distance&#xff0c;简称 GSD&#xff09;是一个非常重要的指标。GSD 是指图像中每个像素在地面上实际代表的物理距离&#xff0c;通常以米或厘米为单位。GSD 决定了图像的空间…...

牛客网 SQL37查找多列排序

SQL37查找多列排序 select device_id,gpa,age from user_profile order by gpa asc,age asc#select [字段1,字段2] from [表名] order by [字段1] [升序(asc)/降序(desc)],[字段2] [升序(asc)/降序(desc)] #select&#xff1a;查询 #order by 排序 每日问题 如何处理对象的状…...

el-tabs标签过多

tab-position&#xff1a;top情况 .el-tabs__nav-wrap{overflow-x: auto ;width: 86% ;margin-left: 10px ; } 效果&#xff1a; tab-position&#xff1a;left情况 .el-tabs__nav-wrap{overflow-x: auto ;height: 高度 ;margin-top: 10px ; } 效果&#xff1a; 注意&…...

如何制作搞笑配音视频?操作方法

在数字娱乐盛行的今天&#xff0c;搞笑配音视频凭借其独特的幽默感和创意&#xff0c;在网络上赢得了大量观众的喜爱。如果你也想尝试制作一部让人捧腹的搞笑配音视频&#xff0c;那么请跟随以下步骤&#xff0c;从撰写搞笑文案到视频配音剪辑&#xff0c;一步步打造你的作品。…...

[Unity]Unity跨平台开发之针对Android开发

用户手册的这一部分包含Android平台关于输入&#xff08;input&#xff09;、资产管理&#xff08;asset management&#xff09;和调试&#xff08;debugging&#xff09;等相关主题的开发信息。 Android移动脚本编写 注意&#xff1a;安卓可以在C#中使用UNITY_ANDROID来进行…...

ELK部署

背景 很多公司还是在单体项目中苦苦挣扎&#xff0c;没有必要上elk系统&#xff0c;大家都懂的一个原则系统的技术栈越多系统越复杂&#xff0c;维护起来也越麻烦&#xff0c;在没有大流量高并发的情况下我们就用单体服务挺舒服。我们行业的特殊性做的都是BTB的项目&#xff0…...

ELK系列-(四)轻量级的日志收集助手-Beat家族

一、前文回顾 ELK系列-&#xff08;一&#xff09;Docker部署ELK核心组件 ELK系列-&#xff08;二&#xff09;LogStash数据处理的瑞士军刀 ELK系列-&#xff08;三&#xff09;Kibana 数据可视化的艺术家 关于部署的整体架构欢迎大家回到前面的文章观看&#xff0c;此处&a…...

NodeJs-包管理工具

包英文单词是 package &#xff0c;代表了一组特定功能的源码集合 管理包的应用软件&#xff0c;可以对包进行 下载安装 &#xff0c; 更新 &#xff0c; 删除 &#xff0c; 上传 等操作 借助包管理工具&#xff0c;可以快速开发项目&#xff0c;提升开发效率 前端常用的包管理…...

AWR microwave office 仿真学习(二)使用多层结构天线/超表面的S参数确定层间距

引言 如果大家有看过一些多层天线或超表面的论文,有两种比较常用的分析方法,等效电路法和传输线分析法,这两种方法都是三维结构的电磁问题转换为二维/集总的电路问题。本文就介绍根据这种思想进行多层结构优化的一种方法:在AWR软件中根据单层结构的S参数,确定最佳层间距。…...

【zlm】 webrtc源码讲解三(总结)

目录 setsdp onwrite ​编辑 play 参考 setsdp onwrite play 参考 【zlm】 webrtc源码讲解_zlm webrtc-CSDN博客 【zlm】 webrtc源码讲解&#xff08;二&#xff09;_webrtc 源码-CSDN博客...

Springboot+Druid(可切换Hikari)+Mybatis-plus+mysql+hive的多数据源项目配置

1.搭建一个springboot项目&#xff0c;不会的搜一下&#xff0c;很简单这里不做赘述。 2.首先你搭建的springboot能正常启动之后&#xff0c;pom文件添加如下依赖&#xff1a; <dependency><groupId>com.alibaba</groupId><artifactId>druid</arti…...

Git使用步骤

Git 是一个分布式版本控制系统&#xff0c;广泛用于软件开发和其他需要跟踪文件变更的项目。以下是 Git 的基本使用方法和一些常用命令的详细说明。 安装 Git 在大多数操作系统上&#xff0c;你可以通过包管理器安装 Git&#xff1a; Windows: 下载并安装 Git for Windows。…...

Python+OpenCV系列:AI看图识人、识车、识万物

在人工智能风靡全球的今天&#xff0c;用 Python 和 OpenCV 结合机器学习实现物体识别&#xff0c;不仅是酷炫技能&#xff0c;更是掌握未来的敲门砖。本篇博文手把手教你如何通过摄像头或图片输入&#xff0c;识别人、动物、车辆及其他物品&#xff0c;让你的程序瞬间具备 AI …...

springboot449教学资源共享平台(论文+源码)_kaic

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统教学资源共享平台信息管理难度大&#xff0c;容错率低&am…...

类OCSP靶场-Kioptrix系列-Kioptrix Level 4

一、前情提要 二、实战打靶 1. 信息收集 1.1. 主机发现 1.2. 端口扫描 1.3.目录遍历 1.4. 敏感信息 2.漏洞发现 2.1.登录框万能密码 2.2.系统用户密码-ssh链接 2.3.mysql-udf提权 一、前情提要 kali黑客-利用searchsploit搜索exp一键化攻击-CSDN博客 一篇文章带你理…...

贪心算法在背包问题上的运用(Python)

背包问题 有n个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和? 这就是典型的背包问题(又称为0-1背包问题),也是具体的、没有经过任何延伸的背包问题模型。 背包问题的传统求解方法较为复杂,现定义有一个可以载重为8kg的背…...

POD 存储、PV、PVC

目录 容器如何持久化存储&#xff1f; PV和PVC 为什么不能直接在 Pod 或容器中存储数据&#xff1f; 什么是 PV和 PVC&#xff1f; 可以使用本地磁盘空间创建PV吗&#xff1f; 如何让客户端通过ftp上传到远端服务器的POD里面&#xff1f; 另一个POD想访问ftp的POD里面的…...

C中strlen和sizeof的区别

1、代码如下&#xff1a; #include<stdio.h>int main() {char a[10] { h,e,l,l,0};printf("%d\n",strlen(a));printf("%d\n", sizeof(a));return 0; } 2、运行结果如下&#xff1a;...

WSL2内部的Ubuntu怎么设置网络内桥接模式,弄了好久老是不成功,怎么办?

环境: Win10专业版 WSL2 Ubuntu22.04 问题描述: WSL2内部的Ubuntu怎么设置网络内桥接模式 解决方案: 方法一 1.控制面板开启,Hyper-V 管理器 2.重启电脑 3…创建外部虚拟交换机 打开 Hyper-V 管理器,在右侧操作面板中点击“虚拟交换机管理器”。 选择“创建虚…...

Linux环境下 搭建ELk项目 -单机版练习

前言 ELK 项目是一个由三个开源工具组成的日志处理和分析解决方案&#xff0c;ELK 是 Elasticsearch、Logstash 和 Kibana 的首字母缩写。这个项目的目标是帮助用户采集、存储、搜索和可视化大量的日志和事件数据&#xff0c;尤其是在分布式系统中。下面是每个组件的概述&…...

ubuntu20.04安装mysql5.7

安装之前要确保之前没安装过或者安装后卸载干净了&#xff0c;不然后面的配置文件可能会报错。 1. 下载安装包 打开链接 downloads.mysql.com/archives/co… 选择相应版本进行下载&#xff0c;这里mysql版本选择 5.7.35&#xff0c;系统选择Ubuntu Linux&#xff0c;选择64位…...