函数栈帧的创建与销毁
函数栈帧的创建与销毁
- 函数栈帧简介
- 认识寄存器
- 解析函数栈帧的创建与销毁
函数栈帧简介
我们在编程的过程中经常会听见函数栈帧这个词汇,那到底什么是函数栈帧呢?接下来就为大家解答一下,我们都知道,一个函数的创建是需要去开辟空间的,而且是在栈区上面开辟的空间(静态函数除外),而这个开辟空间的行为,我们就可以去称之为函数栈帧的创建,当然,他也不仅仅只是单纯的去开辟空间,还伴随着一些其他的行为,后面我们会介绍到。当我们调用完一个函数完毕以后,就会去释放掉申请的空间,这个过程也就称之为函数栈帧的销毁。
函数开辟空间是用来干什么呢?我们在编写代码的过程中经常会创建一些临时变量,会有一些返回值,也会存在一些函数调用的上下文信息;所以函数栈帧开辟出来就是为了去保存这些东西的。
当然,这些东西并不是仅仅保存在函数栈帧开辟的空间里面的,他是会和寄存器存在一些交互操作的,那什么又是寄存器呢?
认识寄存器
寄存器其实就是计算机中访问速度非常快的一块儿内存,从下图中我们就可以看出现代计算机中具有存储功能的部件比对,寄存器的速度是最快的,同时也是造价最高昂的。
关于函数栈帧的创建与销毁我们在这儿就需要理解几个概念:
eax
(累加寄存器,主要作用就是实现乘除运算、中间结果缓存);ebx
(基址寄存器,主要作用就是存储器指针);ecx
(计数寄存器, 主要作用就是实现循环控制、进行串操作);edx
(数据寄存器, 主要作用就是实现乘除运算、中间结果缓存(与eax
类似))。
以上这几种类型的寄存器统称为数据寄存器,同时,我们也需要理解一下下面这几种变址寄存器和指针寄存器:
esi
(源变址寄存器,主要作用就是作为存储器指针、在串指令中作为源操作数指针);edi
(目的变址寄存器,主要作用就是作为存储器指针、在串指令中作为目的操作数指针);ebp
(基址指针寄存器,指向栈帧底部或栈底(栈帧底部和栈底是两个不同的概念));esp
(堆栈指针寄存器,指向栈帧顶部或栈顶(栈帧顶部和栈顶是两个不同的概念))。
接下来我们还需要去了解一些相关的汇编指令:
mov
:将数据从一个地方移动到另一个地方。例如,mov ax, 1234h
将把十六进制数1234h
加载到ax
寄存器。add
:将两个值相加。例如,add ax, 1234h
将把ax
寄存器的当前值与十六进制数1234h
相加,并将结果存储在ax
寄存器中。sub
:从第一个值中减去第二个值。例如,sub ax, 1234h
将从ax
寄存器的当前值中减去十六进制数1234h
,并将结果存储在ax
寄存器中。jmp
:无条件跳转到指定的地址。例如,jmp MyProcedure
将跳转到名为MyProcedure
的程序的开始地址。push
:将一个值推入堆栈。例如,push ax
将把ax
寄存器的当前值推入堆栈中。pop
:从堆栈中弹出一个值,并将其存储在目标操作数中。例如,pop ax 将从堆栈中弹出一个值,并将其存储在 ax 寄存器中。call
:调用一个子程序,并将返回地址压入堆栈。例如,call MyProcedure
将调用名为MyProcedure
的子程序,并将返回地址压入堆栈中。ret
:从堆栈中弹出返回地址,并将控制权转移回调用点。例如,ret
将从堆栈中弹出一个返回地址,并将控制权转移回调用点;lea
:即装入有效地址的意思,它的操作数就是地址。例如,lea eax,[addr]
就是将表达式addr
的值放入eax
寄存器;rep stos
:组合指令实际上是让处理器执行连续的存储操作,将指定的字节或字写入内存中,直到满足某个条件为止,通常用于在内存中填充一段连续的数据。
解析函数栈帧的创建与销毁
在这儿首先我们需要知道栈区的空间是由高地址向低地址进行使用的,函数栈帧开辟的空间是由栈帧顶部和栈帧底部也就是esp
和ebp
两个指针进行维护的。
因为不同的编译器对于函数栈帧的开辟是略有不同的,本次是以VS2019为例。
代码演示
下面以一段简单的代码来对我们的函数栈帧的创建与销毁进行演示:
#include <stdio.h>int Add(int x, int y)
{int z = 0;z = x + y;return z;
}int main()
{int a = 10;int b = 20;int c = 0;c = Add(a, b);printf("%d\n", c);return 0;
}
首先我们使用反汇编工具来查看一下整体的一个汇编代码
int main()
{
00C91820 push ebp
00C91821 mov ebp,esp
00C91823 sub esp,0E4h
00C91829 push ebx
00C9182A push esi
00C9182B push edi
00C9182C lea edi,[ebp-24h]
00C9182F mov ecx,9
00C91834 mov eax,0CCCCCCCCh
00C91839 rep stos dword ptr es:[edi] int a = 10;
00C9183B mov dword ptr [ebp-8],0Ah int b = 20;
00C91842 mov dword ptr [ebp-14h],14h int c = 0;
00C91849 mov dword ptr [ebp-20h],0 c = Add(a, b);
00C91850 mov eax,dword ptr [ebp-14h]
00C91853 push eax
00C91854 mov ecx,dword ptr [ebp-8]
00C91857 push ecx
00C91858 call 00C911BD
00C9185D add esp,8
00C91860 mov dword ptr [ebp-20h],eax printf("%d\n", c);
00C91863 mov eax,dword ptr [ebp-20h]
00C91866 push eax
00C91867 push 0C97B30h
00C9186C call 00C910CD
00C91871 add esp,8 return 0;
00C91874 xor eax,eax
}
接下来,我们就一行一行的进行拆解,最开始就是main函数函数栈帧的创建:
00C91820 push ebp // 首先我们会将ebp的值推入到堆栈当中,也就是栈帧的顶部
00C91821 mov ebp,esp // 将esp的值赋值给ebp
这儿需要注意一下,main
函数也是有其他函数调起来的,所以这儿会存在一个将esp
的值赋值给ebp
操作,后续进入Add
函数以后,就可以明显的理解这一步操作的用意了。
00C91823 sub esp,0E4h // 将esp的值减去一个0E4h(十六进制)
00C91829 push ebx // 将ebx的值推入到堆栈当中
00C9182A push esi // 将esi的值推入到堆栈当中
00C9182B push edi // 将edi的值推入到堆栈当中
00C9182C lea edi,[ebp-24h] // 将ebp-24h的值放入到edi中
00C9182F mov ecx,9 //将9加载到ecx中去
00C91834 mov eax,0CCCCCCCCh // 将0CCCCCCCCh加载到eax中
00C91839 rep stos dword ptr es:[edi] // 将ebp跟ebp-24h之间的空间都初始化为0CCCCCCCC
// 可以翻译为下面的意思
for (int i = ecx ;i>0 ;i--,edi += 4 ){stos dword ptr es:[edi]
}
00C9182C lea edi,[ebp-24h] // 将ebp-24h的值放入到edi中
00C9182F mov ecx,9 //将9加载到ecx中去
00C91834 mov eax,0CCCCCCCCh // 将0CCCCCCCCh加载到eax中
00C91839 rep stos dword ptr es:[edi] // 将ebp跟ebp-24h之间的空间都初始化为0CCCCCCCC
// 可以翻译为下面的意思
for (int i = ecx ;i>0 ;i--,edi += 4 ){stos dword ptr es:[edi]
}
上面这些汇编代码连在一起其实意思就很明显了,就可以看出这段操作其实就是在初始化这段开辟的空间。
接下就是main函数主要的初始化位置的代码:
int a = 10;
00C9183B mov dword ptr [ebp-8],0Ah // 将0Ah(16进制)转化为10进制也就是10,在ebp-8位置初始化int b = 20;
00C91842 mov dword ptr [ebp-14h],14h // 将14h(16进制)转化为10进制也就是20,在ebp-14h位置初始化int c = 0;
00C91849 mov dword ptr [ebp-20h],0 // 将0(16进制)转化为10进制也就是0,在ebp-20h位置初始化
c = Add(a, b);
00C91850 mov eax,dword ptr [ebp-14h] // 将ebp-14h位置的值也就是20放入到eax里面
00C91853 push eax // 把eax推入到堆栈当中
00C91854 mov ecx,dword ptr [ebp-8] // 将ebp-8位置的值也就是10设置进ecx当中
00C91857 push ecx // 把ecx推入到堆栈当中
这一段汇编代码的作用就是将main
函数的形参分别放入到eax
和ecx
寄存器中,在这儿我们就会发现,形参其实就是实参的一份临时拷贝,所以也就是是为什么平时我们经常谈到对于形参的修改,并不会去影响到实参,原因就是在这儿,我们已经将值拷贝到eax
和ecx
寄存器中去了
接下来就是比较重要的一个环节了,这一步就意味着我们此时就需要进入到Add函数当中去了,这儿就是用了call
指令以及jump
指令:
00C91858 call 00C911BD // 调用子程序,并将返回的地址(00C911BD)压入到堆栈当中
00C911BD jmp 00C91760 // 无条件的跳转到00C91760这个地址处,也就是Add函数的位置
将00C91BD
这个地址压入到堆栈当中的目的就是以便于最后函数函数销毁过程中找到回来的位置。
此时我们就进入到了Add
函数当中,那么当前的操作其实就和main
函数函数栈帧的创建很相似了。
int Add(int x, int y)
{
00C91760 push ebp
00C91761 mov ebp,esp
00C91763 sub esp,0CCh
00C91769 push ebx
00C9176A push esi
00C9176B push edi int z = 0;
00C9176C mov dword ptr [ebp-8],0 z = x + y;
00C91773 mov eax,dword ptr [ebp+8]
00C91776 add eax,dword ptr [ebp+0Ch]
00C91779 mov dword ptr [ebp-8],eax return z;
00C9177C mov eax,dword ptr [ebp-8]
}
00C9177F pop edi
00C91780 pop esi
00C91781 pop ebx
00C91782 mov esp,ebp
00C91784 pop ebp
00C91785 ret
首先也介绍一下最开始的部分:
00C91760 push ebp // 将ebp的值推入到堆栈当中
00C91761 mov ebp,esp // 将esp的值赋值给ebp
00C91763 sub esp,0CCh // 将esp的值减去一个0CCh(十六进制)
00C91769 push ebx // 将ebx的值推入到堆栈当中
00C9176A push esi // 将esi的值推入到堆栈当中
00C9176B push edi // 将esi的值推入到堆栈当中
这一段汇编语言其实就是在进入Add函数以开始开辟函数栈帧,然后去完成一些寄存器的赋值工作。
int z = 0;
00C9176C mov dword ptr [ebp-8],0 // 将变量0赋值给ebp-8也就是z变量的位置z = x + y;
00C91773 mov eax,dword ptr [ebp+8] // 将ebp+8位置的值也就是10赋值到eax里面
00C91776 add eax,dword ptr [ebp+0Ch] // 将ebp+0Ch位置的值也就是20与当前eax中的值10相加
00C91779 mov dword ptr [ebp-8],eax // 将eax中的值也就是30放入到ebp-8的位置处return z;
00C9177C mov eax,dword ptr [ebp-8] // 将ebp-8位置的值也就就是30放入到eax中
也就是说,最终我们计算出来相加的这个值是保存在eax
这个寄存器中的,这也就是为什么z
是一个临时变量,但是最终函数栈帧销毁了以后我们依然能return
回去的原因。
00C9177F pop edi // 将edi从堆栈中pop掉
00C91780 pop esi // 将esi从堆栈中pop掉
00C91781 pop ebx // 将ebx从堆栈中pop掉
00C91782 mov esp,ebp // 将ebp的值赋给esp
00C91784 pop ebp // pop掉ebp
00C91785 ret // 从堆栈中弹出返回地址也就是00C911BD这个地址,然后将控制权转移到调用点
接下来就是Add
函数栈帧销毁的过程了,00C911BD
这个地址此时就派上用场了,我们会再次通过这个地址,找到调用点的位置,然后将控制权转移到控制点的位置,也就是跳出Add
函数了,此时就回到了调用call
指令的下一步的位置:
最终的栈帧又变成了main函数开辟的栈帧了。
00C9185D add esp,8 // 将esp的值减去8(16进制)
00C91860 mov dword ptr [ebp-20h],eax // 将eax寄存器中的值也就是30放入到ebp-20h中
此时我们就将对应的计算结果30返回来,Add
函数的函数栈帧此时也已经销毁,但是我们会发现一个非常有意思的现象,尽管Add
函数的函数栈帧已经销毁了,但是Add
函数栈帧当时设置的临时变量的值还是存在的,这个值并没有被销毁,只有当下次某个函数在开辟栈帧时才会将这片栈帧中的值给覆盖掉。
后续的调用其实也就是跟上面的图解几乎差不多了,就不做解释了,以下就是部分汇编代码的解析:
int main()
{
00C91820 push ebp // 首先我们会将ebp的值推入到堆栈当中,也就是栈帧的顶部
00C91821 mov ebp,esp // 将esp的值赋值给ebp
00C91823 sub esp,0E4h // 将esp的值减去一个0E4h(十六进制)
00C91829 push ebx // 将ebx的值推入到堆栈当中
00C9182A push esi // 将esi的值推入到堆栈当中
00C9182B push edi // 将edi的值推入到堆栈当中
00C9182C lea edi,[ebp-24h] // 将ebp-24h的值放入到edi中
00C9182F mov ecx,9 //将9加载到ecx中去
00C91834 mov eax,0CCCCCCCCh // 将0CCCCCCCCh加载到eax中
00C91839 rep stos dword ptr es:[edi] // 将ebp跟ebp-24h之间的空间都初始化为0CCCCCCCC
// 其实这四句汇编代码就可以理解为一个循环,就是将ebp跟ebp-24h之间的9个空间全部初始化为0CCCCCCCCint a = 10;
00C9183B mov dword ptr [ebp-8],0Ah // 将0Ah(16进制)转化为10进制也就是10,在ebp-8位置初始化int b = 20;
00C91842 mov dword ptr [ebp-14h],14h // 将14h(16进制)转化为10进制也就是20,在ebp-14h位置初始化int c = 0;
00C91849 mov dword ptr [ebp-20h],0 // 将0(16进制)转化为10进制也就是0,在ebp-20h位置初始化c = Add(a, b);
00C91850 mov eax,dword ptr [ebp-14h] // 将ebp-14h位置的值也就是20放入到eax里面
00C91853 push eax // 把eax推入到堆栈当中
00C91854 mov ecx,dword ptr [ebp-8] // 将ebp-8位置的值也就是10设置进ecx当中
00C91857 push ecx // 把ecx推入到堆栈当中
00C91858 call 00C911BD // 调用子程序,并将返回的地址(00C911BD)压入到堆栈当中
00C911BD jmp 00C91760 // 无条件的跳转到00C91760这个地址处,也就是Add函数的位置
00C9185D add esp,8 // 将esp的值减去8(16进制)
00C91860 mov dword ptr [ebp-20h],eax // 将eax寄存器中的值也就是30放入到ebp-20h中printf("%d\n", c);
00C91863 mov eax,dword ptr [ebp-20h]
00C91866 push eax
00C91867 push 0C97B30h
00C9186C call 00C910CD
00C91871 add esp,8 return 0;
00C91874 xor eax,eax
}int Add(int x, int y)
{
00C91760 push ebp // 将ebp的值推入到堆栈当中
00C91761 mov ebp,esp // 将esp的值赋值给ebp
00C91763 sub esp,0CCh // 将esp的值减去一个0CCh(十六进制)
00C91769 push ebx // 将ebx的值推入到堆栈当中
00C9176A push esi // 将esi的值推入到堆栈当中
00C9176B push edi // 将esi的值推入到堆栈当中
int z = 0;
00C9176C mov dword ptr [ebp-8],0 // 将变量0赋值给ebp-8也就是z变量的位置z = x + y;
00C91773 mov eax,dword ptr [ebp+8] // 将ebp+8位置的值也就是10赋值到eax里面
00C91776 add eax,dword ptr [ebp+0Ch] // 将ebp+0Ch位置的值也就是20与当前eax中的值10相加
00C91779 mov dword ptr [ebp-8],eax // 将eax中的值也就是30放入到ebp-8的位置处return z;
00C9177C mov eax,dword ptr [ebp-8] // 将ebp-8位置的值也就就是30放入到eax中
}
00C9177F pop edi // 将edi从堆栈中pop掉
00C91780 pop esi // 将esi从堆栈中pop掉
00C91781 pop ebx // 将ebx从堆栈中pop掉
00C91782 mov esp,ebp // 将ebp的值赋给esp
00C91784 pop ebp // pop掉ebp
00C91785 ret // 从堆栈中弹出返回地址也就是00C911BD这个地址,然后将控制权转移会调用点
相关文章:
函数栈帧的创建与销毁
函数栈帧的创建与销毁 函数栈帧简介认识寄存器解析函数栈帧的创建与销毁 函数栈帧简介 我们在编程的过程中经常会听见函数栈帧这个词汇,那到底什么是函数栈帧呢?接下来就为大家解答一下,我们都知道,一个函数的创建是需要去开辟空…...
Scheme语言的算法
Scheme语言的算法探索 引言 Scheme是一种以表达式为基础的编程语言,属于Lisp家族,因其简洁、灵活的语法而受到广泛关注。Scheme不仅适合教学,还被用于实际应用开发和研究。本文将深入探讨Scheme语言的算法,包括其基本特性、常用…...
[C++面试] new、delete相关面试点
一、入门 1、说说new与malloc的基本用途 int* p1 (int*)malloc(sizeof(int)); // C风格 int* p2 new int(10); // C风格,初始化为10 new 是 C 中的运算符,用于在堆上动态分配内存并调用对象的构造函数,会自动计算所需内存…...
(回滚莫队)洛谷 P10268 符卡对决 题解
居然还没调出来?感觉是数据类型的问题,真是吓人。先把思路写一下吧。 题意 灵梦一共有 n n n 张符卡,每张卡都有一个能力值,对于第 i i i 张卡,它的能力值为 a i a_i ai,现在她想从中选出两张符卡并…...
C语言复习笔记--指针(3)
接上篇文章C语言复习笔记--指针(2)-CSDN博客我们继续进行指针的复习. 二级指针 指针变量也是变量,是变量就有地址,那指针变量的地址取出来后要存在在什么变量中呢?这就是⼆级指针. ⼆级指针的运算见下: 指针数组 指针数组概念 既然要联系数组和指针就涉…...
Fastjson 处理 JSON 生成与解析指南
Fastjson 是阿里巴巴开源的高性能 JSON 库,适用于 Java 对象的序列化(生成 JSON)和反序列化(解析 JSON)。以下是详细使用指南: 1. 添加依赖 <dependency><groupId>com.alibaba</groupId>…...
深度学习数据集划分比例多少合适
在机器学习和深度学习中,测试集的划分比例需要根据数据量、任务类型和领域需求灵活调整。 1. 常规划分比例 通用场景 训练集 : 验证集 : 测试集 60% : 20% : 20% 适用于大多数中等规模数据集(如数万到数十万样本),平衡了训练数…...
查询当前用户的购物车和清空购物车
业务需求: 在小程序用户端购物车页面能查到当前用户的所有菜品或者套餐 代码实现 controller层 GetMapping("/list")public Result<List<ShoppingCart>> list(){List<ShoppingCart> list shoppingCartService.shopShoppingCart();r…...
大模型如何引爆餐饮与电商行业变革
大模型如何引爆餐饮与电商行业变革? 一、时代背景:大模型重构产业逻辑的底层动力 1. 技术跃迁催生效率革命 2025年,大模型技术迎来"普惠临界点"。李开复在中关村论坛指出,大模型推理成本每年降低10倍,使得…...
【MySQL】01.MySQL环境安装
注意:在MYSQL的安装与卸载中,需要使用root用户进行。 一、卸载不必要的环境 • 查看是否有运行的服务 [rootVM-24-10-centos etc]# ps axj |grep mysql1 22030 22029 22029 ? -1 Sl 27 0:00 /usr/sbin/mysqld --daemonize --pid-fi…...
java 匿名内部类 和 Lambda 表达式
java 匿名内部类 和 Lambda 表达式 一、匿名内部类1.1说明1.2 匿名内部类的作用1.3 特点1.4 接口的正常使用情况(抽象类同理)1.5 通过局部内部类使用接口(抽象类同理)1.6 通过匿名内部类使用接口(抽象类同理࿰…...
Linux系统调用编程
进程和线程 进程是操作系统资源分配的基本单位,拥有独立的地址空间、内存、文件描述符等资源,进程间相互隔离。每个进程由程序代码、数据段和进程控制块(PCB)组成,PCB记录了进程状态、资源分配等信息。 线程是…...
Redis 数据类型详解
Redis 数据类型详解 Redis 是一个高性能的键值存储系统,支持多种数据类型,每种类型都有其特定的使用场景和操作命令。以下是 Redis 主要数据类型的详细介绍: 一、基本数据类型 1. String(字符串) 特点:…...
orangepi zero烧录及SSH联网
下载对应版本的armbian镜像 armbian的默认用户root,默认密码:1234 下载烧录工具win32diskimager https://sourceforge.net/projects/win32diskimager/files/Archive/ 插入16G以上TF卡,使用win32diskimager烧录armbian镜像 烧录完毕后用l…...
七均线策略思路
一种基于移动平均线的交易策略,具体如下: 1. 移动平均线计算: 计算了六个不同周期的收盘价移动平均值,分别为MA5、MA10、MA20、MA30、MA40和MA60。 2. 买入条件(BK): 当满足以下所有条件时执行买…...
【python脚本】基于pyautogui的python脚本
一、什么是自动化 自动化是指使用技术手段模拟人工,执行重复性任务。准确率100%,高于人工。 自动化应用场景: 自动化测试自动化运维自动化办公自动化游戏 二、pyautogui的使用 先使用 pip install pyautogui 指令安装这个第三方库 2.1 …...
人工智能时代人才培养的变革路径:模式创新、能力重塑与认证赋能
在科技日新月异的今天,人工智能(AI)已成为推动社会进步与经济发展的核心力量。从自动驾驶到医疗诊断,从金融分析到教育创新,AI的触角已延伸至人类生活的每一个角落。这一变革不仅重塑了产业格局,更对人才培养提出了前所未有的挑战与机遇。在人工智能时代,如何培养适应未…...
xpath定位
一、路径符号核心区别(表格速查) 符号名称作用范围典型使用场景性能影响/单斜杠./ 相对路径直接子级, /绝对路劲-根路径精确层级定位高效//双斜杠//当前元素下开始查找,可以跨嵌套层模糊层级/跨嵌套定位较低效 一、XPath基础定位类型&#…...
Python列表(List)深度解析
列表(List)是Python中最基础且强大的数据结构之一,但它的底层实现和特性远比表面看起来复杂。本文将深入探讨列表的各个方面。 1. 列表基础特性 1.1 可变序列类型 lst [1, 2, 3] lst[1] 20 # 可变性1.2 异构容器 mixed [1, "hello", 3.14, [1, 2]…...
Mybatis---入门
1. 什么是MyBatis? MyBatis是⼀款优秀的 持久层 框架,⽤于简化JDBC的开发。 MyBatis本是 Apache的⼀个开源项⽬iBatis,2010年这个项⽬由apache迁移到了google code,并且改名为MyBatis 。2013年11⽉迁移到Github. 官⽹:MyBa…...
FPGA--HDLBits网站练习
目录 用状态机编写一个 LED流水灯代码 CPLD和FPGA芯片 CPLD(复杂可编程逻辑器件) FPGA(现场可编程门阵列) Verilog练习 基本 向量 用状态机编写一个 LED流水灯代码 往期作业已完成,博客地址: FPGA…...
《Linux内存管理:实验驱动的深度探索》【附录】【实验环境搭建 4】【Qemu 如何模拟numa架构】
我们在学习 linux 内核时,会涉及到很多 numa 的知识,那我们该如何在 qemu 中模拟这种情况,来配合我们的学习呢? 我们该如何模拟 如下的 numa 架构 Qemu 模拟 NUMA 架构 -M virt,gic-version3,virtualizationon,typevirt \ -cp…...
如何分析 jstat 统计来定位 GC?
全文目录: 开篇语前言摘要概述jstat 的核心命令与参数详解基本命令格式示例 jstat 输出解读主要字段含义 典型 GC 问题分析案例案例 1:年轻代 GC 过于频繁案例 2:老年代发生频繁 Full GC案例 3:元空间(Metaspace&#…...
Day51 | 3. 无重复字符的最长子串、12. 整数转罗马数字、49. 字母异位词分组、73. 矩阵置零
3. 无重复字符的最长子串 题目链接:3. 无重复字符的最长子串 - 力扣(LeetCode) 题目难度:中等 代码: class Solution {public int lengthOfLongestSubstring(String s) {Set<Character> setnew HashSet<&…...
【Linux系统编程】进程概念,进程状态
目录 一,操作系统(Operator System) 1-1概念 1-2设计操作系统的目的 1-3核心功能 1-4系统调用和库函数概念 二,进程(Process) 2-1进程概念与基本操作 2-2task_struct结构体内容 2-3查看进程 2-4通…...
第二十八章:Python可视化图表扩展-和弦图、旭日图、六边形箱图、桑基图和主题流图
一、引言 在数据可视化领域,除了常见的折线图、柱状图和散点图,还有一些高级图表类型可以帮助我们更直观地展示复杂数据关系。本文将介绍五种扩展图表:和弦图、旭日图、六边形箱图、桑基图和主题流图。这些图表在展示数据关系、层次结构和流量…...
深入理解C++引用:从基础到现代编程实践
一、引用的本质与基本特性 1.1 引用定义 引用是为现有变量创建的别名,通过&符号声明。其核心特点: 必须初始化且不能重新绑定 与被引用变量共享内存地址 无独立存储空间(编译器实现) 类型必须严格匹配 int value 42; in…...
OpenVLA-OFT——微调VLA的三大关键设计:支持动作分块的并行解码、连续动作表示以及L1回归目标
前言 25年3.26日,这是一个值得纪念的日子,这一天,我司「七月在线」的定位正式升级为了:具身智能的场景落地与定制开发商 ,后续则从定制开发 逐步过渡到 标准产品化 比如25年q2起,在定制开发之外࿰…...
linux3 mkdir rmdir rm cp touch ls -d /*/
Linux 系统的初始目录结构遵循 FHS(Filesystem Hierarchy Standard,文件系统层次标准),定义了每个目录的核心功能和存储内容。以下是 Linux 系统初始安装后的主要目录及其作用: 1. 核心系统目录 目录用途典型内容示例…...
TDengine 中的视图
简介 从 v3.2.1.0 开始,TDengine 企业版提供视图功能,便于用户简化操作,提升用户间的分享能力。 视图(View)本质上是一个存储在数据库中的查询语句。视图(非物化视图)本身不包含数据ÿ…...
算法设计学习9
实验目的及要求: 通过排序算法的实验,旨在深化学生对不同排序算法原理和性能的理解,培养其分析和比较算法效率的能力。通过实际编程,学生将掌握排序算法的实现方法,了解不同算法的优劣,并通过性能测试验证其…...
PGSQL 对象创建函数生成工具
文章目录 代码结果 代码 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>PGSQL 函数生成器</tit…...
企业安全——FIPs
0x00 前言 先来看一道题目。这道题目涉及到的就是道德规范和互联网相关内容,本文会对相关内容进行描述和整理。 正确答案是:D 注意FIPs的主要目的是为了限制,也就是针对数据的守则。 0x01 RFC 1087 1989年1月 互联网架构委员会 IAB 发布了…...
历年跨链合约恶意交易详解(二)——XBridge20240424攻击
漏洞合约函数 /*** dev token owner can list the pair of their token with their corresponding chain id* param baseToken struct that contains token address and its corresponding chain id* param correspondingToken struct that contains token address and its cor…...
《AI大模型开发笔记》MCP快速入门实战(一)
目录 1. MCP入门介绍 2. Function calling技术回顾 3. 大模型Agent开发技术体系回顾 二、 MCP客户端Client开发流程 1. uv工具入门使用指南 1.1 uv入门介绍 1.2 uv安装流程 1.3 uv的基本用法介绍 2.MCP极简客户端搭建流程 2.1 创建 MCP 客户端项目 2.2 创建MCP客户端…...
01背包问题:详细解释为什么重量维度必须从大到小遍历。
01背包 问题描述 题目链接:https://www.lanqiao.cn/problems/1174/learning/?page1&first_category_id1&problem_id1174 特点:每件物品只能拿或者不拿。 解法1 设置状态:dp[i][j]指的是前i件物品重量为j的最大价值。 第i件物品…...
Nginx配置伪静态,URL重写
Nginx配置伪静态,URL重写 [ Nginx ] 在Nginx低版本中,是不支持PATHINFO的,但是可以通过在Nginx.conf中配置转发规则实现: location / { // …..省略部分代码if (!-e $request_filename) {rewrite ^(.*)$ /index.php?s/$1 l…...
【KMP】P10915 [蓝桥杯 2024 国 B] 最长回文前后缀|普及+
本文涉及知识点 较难理解的字符串查找算法KMP P10915 [蓝桥杯 2024 国 B] 最长回文前后缀 题目描述 小明特别喜欢回文串,然而回文串太少见了,因此他定义了一个字符串的相同长度的、不相交的前缀和后缀是“回文前后缀”,当且仅当这个前缀和…...
【linux学习】linux系统调用编程
目录 一、任务、进程和线程 1.1任务 1.2进程 1.3线程 1.4线程和进程的关系 1.5 在linux系统下进程操作 二、Linux虚拟内存管理与stm32的真实物理内存区别 2.1 Linux虚拟内存管理 2.2 STM32的真实物理内存映射 2.3区别 三、 Linux系统调用函数 fork()、wait()、exec(…...
构建第一个ArkTS应用:Hello World之旅
# 构建第一个ArkTS应用:Hello World之旅 在鸿蒙应用开发的领域中,ArkTS语言为我们提供了强大而便捷的开发方式。今天,就让我们一起踏上构建第一个ArkTS应用——Hello World的奇妙旅程。 ## 一、创建ArkTS工程 1. 首先,我们要使用…...
Mysql 集群架构 vs 主从复制架构
特性主从复制架构MySQL 集群架构适用场景读多写少的场景;备份;高可用高并发读写、实时交易、高可用性场景可扩展性仅读性能可扩展读写都可以水平扩展高可用性手动切换,有限的高可用支持自动故障转移,强高可用支持部署复杂度较简单…...
国产轻量级多途径无限制的高效下载工具介绍
软件介绍 们在日常中常常有下载各类文件的需求,学习资料也好,娱乐文件也罢。有一款国产的BT下载软件——BitComet(比特彗星),它凭借高效且无限制的特性,在下载爱好者中备受青睐。 BitComet属于轻量级的BT下…...
leetcode数组-长度最小的子数组
题目 题目链接:https://leetcode.cn/problems/minimum-size-subarray-sum/ 给定一个含有 n个正整数的数组和一个正整数 target** 。** 找出该数组中满足其总和大于等于target的长度最小的 子数组 [numsl, numsl1, ..., numsr-1, numsr] ,并返回其长度**…...
如何理解缓存一致性?
缓存一致性是指在多处理器系统或分布式系统中,确保各个处理器核心或节点的缓存数据与主内存以及其他缓存中的数据保持一致的机制和过程。以下从问题产生原因、一致性协议和实现方式等方面进行详细理解: 1. 问题产生的原因 1.1 缓存存在的必要性 在计…...
智能体(Agent)系统源码解析:AI 自动化办公的未来
—从代码到商业落地,如何用Agent重构企业工作流? 一、Agent系统的核心价值 1. 企业办公效率的瓶颈 重复性任务耗时:数据录入、报表生成、邮件处理等占员工 40% 工作时间跨系统协作低效:OA/CRM/ERP数据孤岛,人工搬运错…...
字符串移位包含问题
字符串移位包含问题 #include <iostream> #include <algorithm> using namespace std; int main(){string a,b;cin>>a>>b;//谁长遍历谁if(a.size()<b.size()) swap(a,b);//1-对整个字符串进行移位for(int i0; i<a.size(); i){//每次循环都将第一…...
【JavaScript】原型链 prototype 和 this 关键字的练习(老虎机)
这个老虎机练习主要考察JavaScript中的原型链(prototype)和this关键字的使用。 主要思路 创建三个轮盘(reels)实例:我们需要创建3个独立的轮盘对象,它们都委托(delegate)到基础的ree…...
Windows强制删除任何你想删除的文件和文件夹
Windows强制删除任何你想删除的文件和文件夹 本教程适用于 Windows 10/11 系统,工具和命令均经过验证。 为什么删除会失败? 权限不足:文件或文件夹可能需要管理员权限才能删除。文件被占用:某个程序正在使用目标文件,…...
【MySQL数据库】锁机制
概述 锁:是计算机协调多个进程或者线程并发访问某一资源的机制。在数据库中,除了传统的计算资源(CPU、RAM、IO)的争用以外。数据也是一种供多用户共享的资源。如何保证数据的并发访问的一致性、有效性是所有数据库必须解决的一个…...
JS dom修改元素的style样式属性
1通过样式属性修改 第三种 toggle有就删除 没就加上...