C底层 函数栈帧
文章目录
一,什么是寄存器
二,栈和帧
前言
我们在学习c语言程序的时候,是不是有很多的疑问,如
1,为什么形参不可以改变实参
2,为什么我们编写程序的时候会出现烫烫烫......这个乱码
3,那些局部变量和全局变量为什么是全局变量先在程序中出现,局部变量在后面出现
4,为什么会出现栈溢出错误,栈的大小是怎么弄出来的
5,为什么文件的查找数据需要用流,但是printf和scanf也是寻找数据,为什么不用设置流,难道提前设置好了?
等等一系列的问题,接下来我们就要来学习函数栈帧来知道这些问题
一.什么是寄存器
具有存储功能的硬件
在计算机中,具有的存储功能的硬件有哪些呢?
硬盘 --> 内存 --> 高速缓存 --> 寄存器
(从左到右)
访问的速度和缓存的速度是在增加的
容量的大小是在减少的
价格的大小是在增加的
如果我们考虑外部的存储的话就是这样的
磁带,光盘 --> 硬盘 --> 内存 --> 高速缓存 --> 寄存器(规律和上面的是一样的)
(这里我们生活中所用的u盘其实就是硬盘,只不过把他取出来了)
寄存器
存储的空间只有4Byte为的存储空间(这里说的是32位寄存器,因为很广泛)访问速度也是最快的
那为什么寄存器的访问速度是最快的呢?
因为寄存器是集成在cpu上面的,与内存不同,它是一个独立的空间
寄存器的分类
(寄存器中的E其实是extend的英文缩写,表示把16位寄存器扩展到32位寄存器,没有带E的就是16位寄存器,带E的就是32位,(前面这种在x86框架情况是对的,在其他框架不适用)如在x86-64架构(也称为AMD64)中,寄存器被扩展到64位,如RAX, RBX, RCX, RDX等,这些寄存器可以访问其32位和16位部分,我们要考虑框架和文件)
一般的寄存器:EAX EBX ECX EDX
ax:累积暂存器 bx:基底暂存器 cx:计数暂存器 dx:资料暂存器
索引寄存器:ESI EDI
si:来源索引暂存器 di:目的暂存器
堆叠基底寄存器:ESP EBP
sp堆叠指标暂存器 dp:基底指标暂存器
寄存器的用途
每个寄存器都是有自己各自的专长与特别之处:
一般寄存器
1.EAX(A:accumulation 积累 / accumulate 计算)
1,为“累加器”,进行加法,减法,乘法,除法运算时,被当做累加器使用(体现出加法的原理)
(为整数与浮点数计算的核心寄存器之一)
2,用于保存计算的结果和数据
2.EBX (B:base 基本)
1,用于保存基地址的信息,常用于访问内存的数据与元素
2,用于保存指针和地址信息,方便与其他的内存地址进行运算
3.ECX(C:counter 计数)
1,通常被用为计数器,放到循环与迭代操作,在循环里面ECX是可以用于保存循环次数的,然后自己递减,直到0就停止
4.EDX(D:data 数据)
1,保存数据和计算结果的临时存储
2,用于存储整数除法的余数
总结一下一般寄存器
A是计算,所以是作为四则运算的寄存器(累加器),还有一个额外的功能存储数据和结果
B是基本,所以是保存基地址,用于访问里面的数据与元素,因为存的是地址,所以就很方便利用地址运算
C是计数,所以一般存储循环的条件值,然后自己会自己递减到0然后进行结束
D是数据,这里就是存储数据的,所以可以存储数据和计算结果还有整数的乘法和除法的余数
索引暂存器
1.ESI(S:source 源头)
1,这里主要存储指向源数据的指针和索引,它经常与字符串一起使用,指示要操作的字符串的首地址
(这里的“源数据”指的是在执行某些指令时,需要从中读取数据的内存位置或数据结构)
2.EDI(D:destination目的地)
1,这里存储目标数据的指针和索引,通常指向目标字符串的起始位置,以指示存储的位置
总结一下索引寄存器:
ESI(s 源头)这里是存储指向源数据的开头,以便于可以方便操作这个数据
EDI(d 目标)这里是存储目标数据的开头,方便提示这个存储这个目标数据的位置
堆叠,基底暂存器
1.EBP(B 基底)
1,存储堆栈帧的基地址的指针(很重要)
2,在函数调用的和返回的过程中,主要用于维护栈帧的上下文的数据信息,以便正常访问局部变量,传递参数和保存返回地址
2.ESP(S stack 栈(顶))
1,存储堆栈帧的栈顶的指针(很重要)
2,在函数调用的和返回的过程中,主要用于管理栈帧的内存,当压入栈的数据越多,ESP也会相对移动,可以理解为减少
3.EIP(I instruction)
1,存储下一条需要进行的指令,cpu根据EIP来跟踪程序执行的流程,执行完自动更新EIP指向下一个指令
总结一下堆叠基底暂存器
EBP(B 基底)主要储存基底的地址,所以可以很好管理这些数据
ESP(S 栈(顶))主要储存栈顶的地址,所以可以根据栈顶指针的移动来管理栈的内存
EIP (I(交互))主要是存储下一个指令,方便后续的程序的进行,(可以理解为是为了进行交互)
二,栈和帧
1,栈是什么呢?
数据依次存入栈中,去元素的时候,最先放入的元素最后拿出来,最后放入的元素最先拿出来,这个就是栈
(可以理解为现实生活中的放东西与取东西)
2,函数栈帧的概念
在计算机科学中有这么一个概念,它是指在调用函数的时候,系统为函数调用创建一块内存区域,这块内存区域存储了函数的局部变量,函数的参数,返回地址等信息
这个时候,ESP和EBP是会去维护这个函数的空间,在函数运行的时候,ESP栈顶指针指向栈的头部,EBP指向栈的底部(假设我们整一个main函数)
这个就是我们运行到main函数的时候,所形成的栈帧
3,main函数的压栈过程
在运行调试程序的过程中,我们可以调用堆栈时发现,main函数其实也是被别的函数调用的
分别是_tmainCRTStartup和mainStarup函数,调用的逻辑顺序为
mainStatrup --> _tmainCRTStartup --> main
这个是mainStartup压栈
这个是_tmainCRTStartup压栈
mainStarup函数:非Unicode版本的例程,它负责main函数的初始化
_tmainCRTStartup函数:Unicode版本的例程,他也是负责main函数的初始化,但是它是支持Unicode字符的初始化
Unicode的大概理解:把我们的文字组合起来让计算机认识并表示出来
初始化:1,环境的设置:全局变量的初始化等... 2,命令行参数的解析 3,I/O流的初始化(这个时候我们才可以用到这个printf和scanf的函数输入输出)4信号处理 5,其他系统的初始化
这个可以理解很多问题了,函数的压栈就是这样
三,样例程序的压栈
#include<stdio.h>
int add(int x,int y)
{int z = 0;z = x + y;return z;
}
int main()
{int a = 10;int b = 10;int c = 0;c=add(a, b);printf("%d", c);return 0;
}
1,main函数的构造
(以汇编语言讲述)
常见的汇编语言(这个是截取一个学长的图片)
这个是我们main函数前面还没有调用add函数时候的汇编语言
第一步:
push的作用是把这个东西压入栈中
这里的意思是把ebp这三个压入栈中
图示(有两种情况,会是那种呢?)这里的那个ebp下面的空间是_tmainCRTStartup的
由于2019的vs不可以监视到edp的改变,我们可以通过这个来看,来判断是左图还是右图
我们来监视esp的值是多少
然后打开内存块区寻找ebp的地址(记住这里的ebp不是ebp栈底指针,而是压入到栈的寄存器,一定不要搞混了)我们去内存块区寻找一下这个ebp的地址
这里看到地址为0x0137FA34 我们把这个20445748十进制转换一下,换成十六进制看看是否相同
由于大小端的问题,所以这个是倒着存的,如果想知道为什么倒着存储可以去了解一下大小端,这里我们可以观察到这个esp栈顶指针指向的地址就是ebp上面,右图是对的,所以我们每当我们压入栈数据的时候,这个esp是实时进行变换的
第二步:
mov的作用是把后者赋值给前者
所以这里的作用是把esp的地址赋给ebp那这里的图是什么样的呢?
第三步:
sub的英文的意思是减去的意思前者减去后者这么多
(注:我们下面是高地址,上面为低地址)
在这里是向上增长0E4h(228)这么多的空间(这里的h是十六进制的后缀 )
由于vs2019无法观察这个过程,所以建议读者可以去寻找vs2013去学习,这样可以更加直观,所以这里就是在创建一个空间
第四步:
这里的ebx,esi,edi都是非易失寄存器(什么事非易失寄存器呢?就是在电源关闭的时候,也可可以保存其中的内容)那么我们怎么画这个时候的图呢?要记得我们在操作的时候,这个esp栈顶指针是会改变的
这个操作就是把这几个寄存器压入栈里面去
第五步:
lea全名是lead effective address加载有效地址
从此处正式加载当前函数的有效栈区域
这里是把ebp-24h这个地址存放在edi里面(我们来回顾一下edi,在下面)这个是存储一个这个这么大的空间的指针,为了准备一个内存区域用于存储函数的局部变量等的数据,有了这个edi才可以找到这个地方的首地址,才可以确保数据的正常存储
(注:因为这个vs2019这个是根据你写的代码所写的汇编语言,每个编译器都是不一样的,如果你在main函数里面不断写入变量,这个就是会改变的)(其实VS2013真正的写的是[ebp-0E4h]的)
栈开辟之后是不可以改变的,如果超出了栈就会报栈溢出错误,一般来说都是200多M的大小一个函数,这里的操作就是正式的开辟一个空间
EDI(D:destination目的地)
1,这里存储目标数据的指针和索引,通常指向目标字符串的起始位置,以指示存储的位置
我们来看看vs2019变化里面的变量后会怎么样
这个是我们加了变量之后这个变成了ebp-48h了,所以可看到不同的编译器所编写的栈帧都是不一样的
第六步:
这里就是把9赋值给ecx寄存器,0CCCCCCCCh赋值给eax中
第七步:
我们把这个代码拆开来理解:
1,rep这个是一个前缀指令,用于重复执行紧跟其后面的指令(直到ecx为0)
2,stos(全名store String存储字符串)
把eax的内容赋值到edi所指向的地址中,并把edi递增,逐步的把这个全部填满这个空间
3,dword(全名double word指4个字节,word是指2个字节)
4,ptr 这个是操作数的大小提示符号,比如这里就是告诉编译器,这个是4个字节4个字节输入,顺便告诉编译器,接下来是按照特定的字符大小进行操作的,比如这里的4个字节
5,es:这个是寄存器的前缀,用于指定内存操作
6,[edi] 这个是指是edi这个指向的内存
总体来说,就是每次想edi指向的地址一4个字节的大小不断地把eax存储的值传入进去
那么这里的ccccccccc是什么呢?我们之前不是会遇到烫烫烫这一长串的代码嘛?其实就是这个ccccccc弄出来的,比如变量为初始化,打出的乱码就是烫烫烫,这个烫烫烫实质就是cccccc
程序走到了这里,main函数的帧栈正式开辟成功,这个是有esp和edp形成的区域为一个函数的作用域接下来就是执行main函数内部的东西了
2,生成局部量
这个我们以a为例子:
0Ah其实就是把十六机制转换成十进制,这个就是10的意思,然后这个后面就是把0Ah赋给a这个地址,其他都是一样的
3,main函数的总结
接下来呢,我们main函数里面的就基本结束了,后面就是add函数的了,我们来总结一下这个main函数是怎么操作的
1,首先就是把一个ebp压入栈中,然后ebp这个是用来代表基地址的或者就是说存放了基地址
2,我们利用edp这个指向esp的位置,是我们这个ebp进行调位置,指向main的基地址
3,我们利用esp这个减去一个数值使esp来想上移动,然后就是给main函数一个预留一个空间
4,我们利用edi的赋值,正式把这个地址赋值给edi,可以把更好的寻找到这个空间的首地址,所以就是相当于正式开辟了一个内存空间,这个空间大小就是我们所预留的空间大小
5,然后对于这个空间里面进行初始化,把这里面填满c这个东西然后给ecx传值
6,对于局部变量的生成利用mov这个指令
接下里就是add这个函数的分析了
4,调用函数与传参
前面四行代码
前面两行:显然是把b的地址的值通过mov的指令”拷贝”到eax里面去,(这个mov是其实是转移的意思,也可以理解为拷贝的意思)然后把eax压入到栈中,
后面两行:显然也是把a的地址的值通过mov的指令“拷贝”到ecx里面去,然后就把ecx压入到栈里面去
我们来画一下这个图示:
为什么我们要有这四行指令,这个其实就是把形参压入栈里面去了,这里我们就可以了解到,其实形参和实参是处于两个独立的空间的,所以我们就可以知道为什么形参的改变不了实参了,答案就在这里(所以这四行代码就是建立形参用的)
一到四行是为形参做准备,那这样的压入栈中真的可以把参数传入到函数里面吗?调用的函数该怎么使用我们的参数? 我们继续往下看
第五行
call指令:这里其实就是一个转移指令符,转移到另外一个地方去,同时也是为了完成转移后完成原区域的下一个指令,那他是怎么实现这个功能的呢?我们继续详细了解,call指令时把我们下一个指令压入栈中,然后这样的话就可以实现转移后可以返回到原地
(简单来说:原地插个眼后传送去支援,最后还可以返回到线上,做到有来有回)
我们来看看真的是这样嘛,由于vs2019是不支持看这个的,所以你们可以下载vs2013点击F11,然后就可以看到类似于这个的声明
这个就是对于add的一个声明,然后这里有个jmp的指令,这里就是跳入add函数的意思,为转换的操作,我前面画的那个方框是那个地址,应该是call后面的那个地址
应该是相同的(这个我是找了别的图,所以不同,因为vs2019弄不出来,我在网上找了一个这个指令,就是想告诉读者有这个操作) 接下来就是正式跳转到add函数了
5,Add函数
add函数的创建:
我们先来看这个,这个是不是似曾相识,没错跟我们创建main函数的方式一模一样,读者可以尝试自己去解读一下,这样可以让自己的形象更加深刻,我把答案写到下面了
我们来看看现在的栈帧的图该怎么画
变量的生成 运算:
这个局部变量的形成是跟前面一样的,这里就不多讲了,我来看看后面的
第一句是把形参x放入到eax中,因为eax的用处有可以用与加法,然后第二句再把这个y放入到这个eax中,然后根据add指令执行相加,我们就的道了结果,然后再把eax的值拷贝给z这个变量,这个z里面去,这个就是运算(形参的压入顺序是按照从左往右的根据你设置的函数)
函数的返回值和函数返回与销毁的实现:
我们按照前面所学的,x,y,z都是在函数调用完会被销毁的
问题1:我们该怎么获取这个返回值?
问题2:esp栈顶指针和ebp栈底指针该何去何从?
我们先来看这个return这个代码
这里是把z的值存储到eax中,因为我们知道eax的一个用处是存储数据和运算结果,把他临时放入到eax中就可以把值返回了,第一个问题就迎刃而解了
(当然值超出了eax的范围,就要用到其他寄存器存储了,比如esi等其余寄存器存储)
我们再来看看后面的销毁与返回怎么实现的呢我们来看这个指令
pop指令指跳出栈,将元素弹出栈以此释放掉
这个是把是三个非易使寄存器给弹出去,释放掉他们三个(注意这个esp栈顶指针的位置是会变化的)
(这里是弹出三个寄存器)
这个的用处,栈不是弹出来了那三个寄存器嘛,然后就要收缩调整栈,你看0CCh不正是我们之前所弄出来的空间大小嘛
(这里是栈的收缩调整)
这两行指令其实就是检查是否有栈溢出的哪些错误
cmp这个指令是比较两个
比较基指针EBP和栈指针ESP的值。这通常用于检查栈是否正确对齐,或者在调试时检查栈是否被破坏。
call这一段
调用运行时检查函数 __RTC_CheckEsp ,这个函数可能是用于检查栈溢出或栈保护的。 051244h 是该函数在内存中的地址。这个调用可能是由编译器插入的,用于在运行时检查栈指针是否在函数调用后仍然有效,以防止栈溢出攻击或检测栈损坏
(这两个是检查安全性的)
我们来看后面的指令
第一行就是把ebp的值赋给esp,然后ebp会读取地址,然后转移到之前main函数的基地址,之后再让ebp读取之前的那个地址,这里的pop是pop另外一个功能,是读取数据的功能,实现了这个esp和ebp的转移
根据这个转移,最后把这个弹出即可,然后就可以跟着下一个指令了
这里的ret是把栈顶的字节安远出栈,然后交给EIP来处理,这样就可以紧接着这个后面程序的执行即可
我来总结一下add函数的过程:
1,我们先进入函数的调用,先把形参压入到栈里面,然后利用call进入到那个函数的声明的地址哪里并且把下一个指令压入到栈里面去,然后再利用jmp跳入到那个函数里面
2,我们在把局部变量弄出来,然后利用add和eax这两个弄西进行运算,最后赋值给z
3,然后把z的值暂存储在eax中
4,运行返回时,我们就把三个寄存器弹出去,然后ebp会赋给esp,ebp会读取之前的ebp地址进行跳转,然后就可以实现这个esp和edp返回原位置
5,利用ret来实现后面的程序即可
总结
上面的文章里面都有每小段的总结,我们可以根据这些可以解决很多问题
相关文章:
C底层 函数栈帧
文章目录 一,什么是寄存器 二,栈和帧 前言 我们在学习c语言程序的时候,是不是有很多的疑问,如 1,为什么形参不可以改变实参 2,为什么我们编写程序的时候会出现烫烫烫......这个乱码 3,那些局…...
Linux系统编程——进程替换
目录 前言 二、进程程序替换的概念 三、进程程序替换的原理 编辑 四、为什么需要进行进程程序替换 五、如何进行进程程序替换 1、进程替换函数: 1)execl()函数 2)execv()函数 3) execlp()函数 4) execvp()函数 5)execle函数 6)ex…...
PVE中VLAN的设置要点
使用这个拓扑进行连接无法直接访问PVE PVE 设置如下: 核心重点:PVE 的 vmbr0 接口直接绑定了 enp2s0,这会导致 VLAN 流量无法正确处理,因为 PVE 没有专门为 VLAN 3 配置接口。 1.vmbr0 和 vmbr0.3 都是绑定在物理接口 enp2s0 上&…...
零基础Python学习
1.环境搭建 1.1 安装运行环境python3.13 Welcome to Python.org 1.2 安装集成开发环境PyCharm PyCharm: the Python IDE for data science and web development 1.3 创建项目 && 设置字体 2.基础语法 2.1 常量与表达式 在python中整数除整数不会优化,所…...
命令提示符窗口(CMD)控制windows操作系统
一、关于进程 1. 通过进程ID结束进程: taskkill /PID 进程ID 2. 通过进程名称结束进程 taskkill /IM 进程名称.exe 3. 强制结束进程 taskkill /F /IM 进程名称.exe 4. 结束包含特定字符串的全部进程 taskkill /IM 包含字符串* /T 5. 启动一个新的命令行窗口来运行指…...
虚幻引擎5(Unreal Engine 5)高级教程
虚幻引擎5(Unreal Engine 5)高级教程 引言 虚幻引擎5(Unreal Engine 5,简称UE5)是Epic Games推出的一款功能强大的游戏引擎,广泛应用于游戏开发、影视制作和虚拟现实等领域。UE5以其先进的图形渲染技术、…...
3DMAX星空图像生成器插件使用方法详解
3DMAX星空图像生成器插件,一键生成星空或夜空的二维图像。它可用于创建天空盒子或空间场景,或作为2D艺术的天空背景。 【主要特点】 -单击即可创建星空图像或夜空。 -星数、亮度、大小、形状等参数。 -支持任何图像大小(方形)。…...
【QNX+Android虚拟化方案】129 - USB眼图参数配置
【QNX+Android虚拟化方案】129 - USB眼图参数配置 1. 软件侧dts如何配置眼图参数 及 其对应关系2. 硬件 QNX 侧调试眼图命令2.1 High Speed USB2.0 Host2.2 Super Speed USB3.0 Host3. 硬件 Android 侧调试眼图命令基于原生纯净代码,自学总结 纯技术分享,不会也不敢涉项目、不…...
Linux内核4.14版本——ccf时钟子系统(3)——ccf一些核心结构体
目录 1. struct clk_hw 2. struct clk_ops 3. struct clk_core 4. struct clk_notifier 5. struct clk 6. struct clk_gate 7. struct clk_divider 8. struct clk_mux 9. struct clk_fixed_factor 10. struct clk_fractional_divider 11. struct clk_multiplier 12…...
服务器遭受DDoS攻击后如何恢复运行?
当服务器遭受 DDoS(分布式拒绝服务)攻击 后,恢复运行需要快速采取应急措施来缓解攻击影响,并在恢复后加强防护以减少未来攻击的风险。以下是详细的分步指南: 一、应急处理步骤 1. 确认服务器是否正在遭受 DDoS 攻击 …...
js原型、原型链和继承
文章目录 一、原型1、prototype2、constructor 二、原型链1、字面量原型链2、字面量继承3、构造函数的原型链4、Object.create5、Object.setPrototypeOf 三、继承1、构造函数继承2、原型链继承3、组合继承 四、常见链条1、Function2、Object.prototype 继承是指将特性从父代传递…...
看不见的彼方:交换空间——小菜一碟
有个蓝色的链接,先去看看两年前的题目的write up (https://github.com/USTC-Hackergame/hackergame2022-writeups/blob/master/official/%E7%9C%8B%E4%B8%8D%E8%A7%81%E7%9A%84%E5%BD%BC%E6%96%B9/README.md) 从别人的write up中了解到&…...
传奇996_38——称号系统
记住: 称号是装备,加属性的 特效是顶戴,加特效的 需要两个命令分开设置,称号和特效不关联 角色-称号栏显示的图标:由装备表字段,背包显示Looks控制,图片位置在:stab\res\private\t…...
C++:异常
---什么是异常? 异常是面向对象语法处理错误的一种方式。 ---C语言传统的处理错误的方式有哪些呢? 1.返回错误码,有些API接口都是把错误码放到errno中。 2.终止程序,比如发生越界等严重问题时,我们也可以主动调用exit…...
winScp连接Ubantu系统,访问拒绝的解决方式
一、原理分析 win10系统能够通过WinScp连接到Ubantu系统的前提是Ubantu系统开启ssh服务 二、解决步骤 1、Ubantu系统开启ssh服务 更新软件列表 sudo apt update安装OpenSSH服务器 sudo apt install openssh-server开启SSH服务 service sshd start到此,winScp…...
Oracle 建表的存储过程
建表的存储过程 下面是建表的存储过程,用途:通过不同的表,根据不同过滤条件,得到某个字段,例如neid,然后创建一个新表T,表T的表名为拼接XXXX_XXX_neid,表T的字段自行添加 xxx&…...
芯科科技率先支持Matter 1.4,推动智能家居迈向新高度
Matter 1.4引入核心增强功能、支持新设备类型,持续推进智能家居互联互通 近日,连接标准联盟(Connectivity Standard Alliance,CSA)发布了Matter 1.4标准版本。作为连接标准联盟的重要成员之一,以及Matter标…...
pandas快速解决空列表问题
在使用 Pandas 处理数据时,我们经常会遇到包含空列表(即空值或缺失值)的问题。Pandas 提供了一些非常有效的方法来处理这些空列表,使得数据清理和预处理变得更加简单和高效。 以下是一个示例,展示如何使用 Pandas 快速…...
sentinel使用手册
1.引入依赖 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency>2.yaml spring:cloud:sentinel:transport:dashboard: localhost:8090 #sentinel控制台地址…...
【继承】—— 我与C++的不解之缘(十九)
前言: 面向对象编程语言的三大特性:封装、继承和多态 本篇博客来学习C中的继承,加油! 一、什么是继承? 继承(inheritance)机制是⾯向对象程序设计使代码可以复⽤的最重要的⼿段,它允许我们在保持原有类…...
腾讯微众银行大数据面试题(包含数据分析/挖掘方向)面试题及参考答案
为什么喜欢使用 XGBoost,XGBoost 的主要优势有哪些? XGBoost 是一个优化的分布式梯度增强库,在数据科学和机器学习领域应用广泛,深受喜爱,原因主要在于其众多突出优势。 首先,它的精度高,在许多机器学习竞赛和实际应用中,XGBoost 都展现出卓越的预测准确性。其基于决策…...
组合数练习题——c++
题目设置: 现在有x个相同的小球,分给y个人,每个人至少分k个,请问有多少种可能的分发方法,由于结果可能较大,答案对10^97取模。 输入格式: 一行3个整数:x,y, k…...
Java:JPMS模块化开发
JPMS(Java Platform Module System)简介 为什么用JPMS? JPMS(Java 平台模块系统)是 Java 9 引入的模块化系统,也称为 Jigsaw 项目。它为 Java 提供了更精细的模块化机制,用于组织和管理代码&a…...
Spring Boot中配置Flink的资源管理
在 Spring Boot 中配置 Flink 的资源管理,需要遵循以下步骤: 添加 Flink 依赖项 在你的 pom.xml 文件中,添加 Flink 和 Flink-connector-kafka 的依赖项。这里以 Flink 1.14 版本为例: <!-- Flink dependencies --><de…...
【ruby on rails】dup、deep_dup、clone的区别
一、区别 dup 浅复制:dup 方法创建对象的浅复制。 不复制冻结状态:dup 不会复制对象的冻结状态。 不复制单例方法:dup 不会复制对象的单例方法。 deep_dup 深复制:deep_dup 方法创建对象的深复制,递归复制嵌套的对象。…...
鸿蒙开发-HMS Kit能力集(应用内支付、推送服务)
1 应用内支付 开发步骤 步骤一:判断当前登录的华为账号所在服务地是否支持应用内支付 在使用应用内支付之前,您的应用需要向IAP Kit发送queryEnvironmentStatus请求,以此判断用户当前登录的华为帐号所在的服务地是否在IAP Kit支持结算的国…...
springboot中使用mongodb完成评论功能
pom文件中引入 <!-- mongodb --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> yml中配置连接 data:mongodb:uri: mongodb://admin:1234561…...
南京仁品耳鼻喉专科医院:12月启动公益义诊月
专业医疗资源送至“家门口”!南京仁品耳鼻喉专科医院启动公益义诊月 随着2024年即将步入尾声,南京仁品耳鼻喉医院为回馈社会,提升公众健康福祉,将于12月隆重推出“三甲专家公益义诊月”活动。此次活动旨在通过汇聚众多耳鼻喉领域…...
微信小程序首页搜索框的实现教程
微信小程序首页搜索框的实现教程 前言 在现代移动应用中,搜索功能是用户获取信息的主要方式之一。对于购物小程序而言,提供一个美观且高效的搜索框,可以显著提升用户体验,帮助用户快速找到他们想要的商品。本文将详细介绍如何在微信小程序中实现一个样式优美的搜索框,包…...
Educational Codeforces Round 151 (Rated for Div. 2)
题目链接 B. Come Together 题意 输入 输出 思路 可以将B、C坐标作A的变换,将A平移至原点,然后分情况讨论: B、C两点都在轴上,具体分为同向轴和其他情况B、C两点都在象限中,具体分为相同象限、对角象限和相邻象限分别位于象限…...
第二十一天 深度学习简介
深度学习(Deep Learning,简称DL)是机器学习的一个分支,它通过构建和训练深层神经网络模型,从数据中学习和提取特征,以实现复杂任务的自动化处理和决策。以下是对深度学习的详细介绍: 一、起源与…...
mongodb/redis/neo4j 如何自己打造一个 web 数据库可视化客户端?
随笔 从千万粉丝“何同学”抄袭开源项目说起,为何纯技术死路一条? 数据源的统一与拆分 监控报警系统的指标、规则与执行闭环 我们的系统应该配置哪些监控报警项? 监控报警系统如何实现自监控? java 老矣,尚能饭否ÿ…...
elementUI如何dialog对话框 不设置 点击遮罩层 自动关闭的功能
背景 用户在填写dialog对话框的时候,有时候误触 遮罩层,导致form表单直接关闭,用户的信息丢失 代码 要使对话框在点击遮罩层时关闭,您需要在 el-dialog 组件上将 close-on-click-modal 属性设置为 false。以下是更新后的代码&…...
循环神经网络:从基础到应用的深度解析
🍛循环神经网络(RNN)概述 循环神经网络(Recurrent Neural Network, RNN)是一种能够处理时序数据或序列数据的深度学习模型。不同于传统的前馈神经网络,RNN具有内存单元,能够捕捉序列中前后信息…...
LeetCode 100.相同的树
题目: 给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。 思路:灵神 代码: class Solution {public boolean…...
序列化与反序列化
序列化是将对象转换为可被存储或传输的格式,例如将对象转换为字节流或字符串。序列化的过程可以将对象的状态保存下来,以便在需要时可以重新创建对象。 反序列化则是将序列化的对象转换回原始的对象形式,以便可以使用和操作这些对象。 序列…...
spring boot打包fat jar
所谓fat jar就是包含所有依赖的jar以及其他开发的代码的jar包。可以通过java -jar xxx.jar直接启动运行,不需要部署到tomcat中间件就能运行。 接下来我们使用maven进行打包: (1)在需要带包的主模块的pom中添加build依赖…...
2021年美亚杯电子数据取证大赛-个人赛
资格赛-案件背景 2021年10月某日早上,本市一个名为"大路建设"的高速公路工地主管发现办公室的计算机被加密并无法开启,其后收到了勒索通知。考虑到高速公路的基建安全,主管决定报警。警方调查人员到达现场取证,发现办公…...
用 React 编写一个笔记应用程序
这篇文章会教大家用 React 编写一个笔记应用程序。用户可以创建、编辑、和切换 Markdown 笔记。 1. nanoid nanoid 是一个轻量级和安全的唯一字符串ID生成器,常用于JavaScript环境中生成随机、唯一的字符串ID,如数据库主键、会话ID、文件名等场景。 …...
泛型擦除是什么?
泛型擦除(Type Erasure)是Java编译器在编译泛型代码时的一种机制,它的目的是确保泛型能够与JAVA的旧版本(即不支持泛型的版本)兼容。泛型擦除会在编译时移除泛型类型信息,并将泛型类型替换为其非泛型的上限类型(通常是Object) 详细解释 在Java中&#…...
鸿蒙Next星河版基础代码
目录: 1、鸿蒙箭头函数的写法2、鸿蒙数据类型的定义3、枚举的定义以及使用4、position绝对定位及层级zIndex5、字符串的拼接转换以及数据的处理(1)字符串转数字(2)数字转字符串(3)布尔值转换情况(4)数组的增删改查 6、三元表达式7、鸿蒙for循环的几种写法7.1、基本用…...
物联网智能项目:智能家居系统的设计与实现
物联网(Internet of Things,IoT)技术正在迅速改变我们的生活方式,特别是在智能家居、工业自动化、环境监控等领域。物联网智能项目通过将设备、传感器、控制器等通过互联网连接,实现设备间的智能交互,带来高效、便捷和智能的体验。本文将介绍一个典型的物联网智能家居项目…...
STL算法之set相关算法
STL一共提供了四种与set(集合)相关的算法,分别是并集(union)、交集(intersection)、差集(difference)、对称差集(symmetric difference)。 目录 set_union set_itersection set_difference set_symmetric_difference 所谓set,可细分为数学上定义的和…...
STM32主要功能
STM32 是由意法半导体(STMicroelectronics)推出的一系列基于 ARM Cortex-M 内核的微控制器(MCU)。STM32 微控制器广泛应用于嵌入式系统中,因其高性能、低功耗、丰富的外设接口和多种封装形式而被广泛采用。其主要功能和…...
【数据结构】--ArrayList与顺序表
文章目录 1. 线性表2. 顺序表3. ArrayList简介4. MyArrayList的实现5. ArrayList使用5.1 ArrayList的构造5.2 ArrayList常见操作5.3 ArrayList的遍历5.4 ArrayList的扩容机制 6. ArrayList的具体使用6.1 简单的洗牌算法6.2 杨辉三角 1. 线性表 线性表(linear list&…...
多线程篇-3--java内存模型(主内存,共享内存,三大特性,指定重排)
Java内存模型 Java Memory Model,简称JMM,本身是一种抽象的概念,实际上并不存在,它描述的是一组规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素࿰…...
Android Studio的AI工具插件使用介绍
Android Studio的AI工具插件使用介绍 一、前言 Android Studio 的 AI 工具插件具有诸多重要作用,以下是一些常见的方面: 代码生成与自动补全 代码优化与重构 代码解读 学习与知识获取 智能搜索与资源推荐实际使用中可以添加注释,解读某段代…...
【Yarn Bug】 yarn 安装依赖出现的网络连接问题
最近,在初始化 Ant Design Pro 前端脚手架过程中,使用 yarn 安装依赖时遇到了网络连接问题,具体错误信息提示为 info There appears to be trouble with your network connection. Retrying...。通过百度查询,得知出现这种问题的原…...
Vue3的Setup语法动态获取Dom或调用子组件方法
官方文档:https://cn.vuejs.org/api/composition-api-setup.html#composition-api-setup 获取Dom <template><div class"todo" ref"todoDom" click"handleClick"></div> </template><script lang"t…...
中科院一区算法KO-K均值优化算法(K-means Optimizer)-附Matlab免费代码
首先,使用K-means算法在每次迭代中建立聚类区域的形心向量,然后KO提出两种移动策略,以在开发和探索能力之间建立平衡。每次迭代中探索或开发的移动策略的决定取决于一个参数,该参数将被设计为识别每个搜索代理是否在访问的区域中过…...