探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

这篇具有很好参考价值的文章主要介绍了探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』..

目录

知识点回顾

一、什么是栈帧(堆栈帧)?

1.内存布局

2.常用寄存器

3.汇编指令

👇👇对于栈的详细介绍 :

👇👇函数栈帧的介绍:

二、函数调用中的栈帧

1.探究main函数栈帧的创建

2.对main函数中的代码进行分析

3.探究Add函数栈帧的创建 

三、函数栈帧的销毁过程


博客引用相关文献:1.《程序员的自我修养——链接、装载与库》

2.西安比特教育科技.《C语言进阶_动态内存管理》

👻内容专栏:《C/C++学习专栏》

🐨本文概括:讲解函数栈帧创建与销毁的具体过程

🐼本文作者:花 碟

🐸发布时间:2023.4.19

知识点回顾

前期我们学习的时候,对许多知识可能有很多困惑。

比如:

  • 局部变量是怎么创建的?
  • 为什么局部变量创建后默认是随机值?
  • 函数是怎么传参的?传参的顺序是怎么样的?
  • 形参和实参的关系是怎么样的?
  • 函数调用是怎么做的?
  • 函数调用结束后是怎么返回的?

还弄不清?没关系,相信聪明的小伙伴们学习此篇章的函数栈帧知识,以上问题就会迎刃而解啦!

OK,让我们来揭开函数栈帧的创建与销毁的神秘面纱吧~~

一、什么是栈帧(堆栈帧)?

在了解函数栈帧之前,我们不得不先了解一下内存布局、寄存器、汇编指令相关概念。

1.内存布局

C/C++内存布局中的几个区域:

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

1.栈区(stack): 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。栈是向下增长的。栈区是向下生长的,也就是说,栈顶的地址是最小的。栈区的大小是有限制的,如果超出了栈的大小,就会发生栈溢出错误。

2.堆区(heap):堆区是由程序员手动分配和释放的内存区域,用于存储动态分配的内存。堆区是向上生长的,也就是说,堆顶的地址是最大的。堆区的大小是没有限制的,但是如果没有及时释放内存,就会导致内存泄漏。

3.数据段(静态区static):存放全局变量、静态数据。程序结束后由系统释放。

4.代码段:存放函数体(类成员函数和全局函数)的二进制代码。

2.常用寄存器

eax、ebx、ecx、edx、esp、ebp是x86架构CPU中比较常见的寄存器,它们的含义和作用如下:

  1. eax寄存器:又称为累加器寄存器(Accumulator Register),通常用于存储算术计算的操作数和结果。在函数调用时,EAX寄存器也用于保存函数返回值。

  2. ebx寄存器:又称为基址寄存器(Base Register),通常用于存储内存地址信息。在处理数据时,EBX寄存器可以作为一个指针来访问内存。

  3. ecx寄存器:又称为计数器寄存器(Counter Register),通常在循环中使用,用于对循环次数进行计数,并控制循环的结束。

  4. edx寄存器:又称为数据寄存器(Data Register),通常用来存储数据,例如两个操作数的乘积,以及一些特定系统调用的参数。

  5. esp寄存器:又称为栈指针寄存器(Stack Pointer Register),用于指向当前栈顶的位置,也就是最后压入栈中的数据的地址。在函数调用时,ESP寄存器也用于保存当前函数的栈帧信息。

  6. ebp寄存器:又称为基址指针寄存器(Base Pointer Register),用于指向当前栈帧的基地址,也就是当前函数栈帧在栈中的起始位置。在函数调用时,EBP寄存器可以用来定位本地变量和函数参数。

  7. esi寄存器:又称为源索引寄存器(Source Index Register),通常用于存放源数据地址,在计算机复制、移动、传输等操作中扮演着重要角色。

  8. edi寄存器:又称为目标索引寄存器(Destination Index Register),通常用于存放目标数据地址,在计算机复制、移动、传输等操作中也扮演着重要角色

3.汇编指令

  1. MOV:将数据从一个地方移动到另一个地方,例如将一个寄存器中的值移动到另一个寄存器、内存地址或立即数中。

  2. ADD/SUB:加法和减法指令,可以将两个操作数相加或相减,并将结果保存在目标寄存器或内存位置中。

  3. CMP:比较两个操作数并设置标志位,用于支持条件跳转等操作。

  4. JMP:无条件跳转指令,跳转到指定的代码位置执行。

  5. CALL/RET:用于函数的调用与返回,CALL指令将当前程序计数器(PC)入栈并跳转到指定位置,RET指令从堆栈中弹出PC并跳转回调用函数的位置。

  6. PUSH/POP:用于堆栈操作,PUSH指令将数据压入堆栈顶,POP指令将数据从堆栈顶弹出。

  7. NOP:空指令,不执行任何操作,通常用于占位或调试。

  8. XOR/OR/AND:逻辑运算指令,XOR进行异或运算,OR进行或运算,AND进行与运算。 

👇👇对于栈的详细介绍 :

🏷️在经典的计算机科学中,栈被定义为一个特殊的容器,用户可以将数据压入栈中(简称:压栈push),也可以将已经压入栈中的数据弹出(简称:出栈pop),但栈这个容器必须遵守一条规则:先入栈的数据后出栈(First In Last Out,FIFO),多多少少像叠成一摞的书籍📚:先叠上去的书在最下面,因此要最后才能取出。

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🏷️ 栈是一个具有以上属性的动态内存区域。程序可以将数据压入栈中,也可以将数据从栈顶弹出。压栈操作使得栈增大,而出栈操作使栈减小。

👇👇函数栈帧的介绍:

esp(Extended Stack Pointer)为扩展栈指针寄存器,是指针寄存器的一种,用于存放函数栈顶指针。与之对应的是ebp(Extended Base Pointer),扩展基址指针寄存器,也被称为帧指针寄存器,用于存放函数栈底指针

我们知道,在操作系统里,栈总是向下增长的(高地址向低地址增长)。在i386下,栈顶由esp的寄存器进行定位。压栈的操作使栈顶的地址减小,弹出的操作使栈顶地址增大。观察下方描述图,这里栈底指针的地址是0xbfffffff,而esp栈顶指针标明了栈顶,地址为0xbffffff4。在栈上压入数据会导致esp减小,弹出数据使得esp增大。相反,直接减小esp的值也等效于在栈上开辟空间,直接增大esp的值等价于在栈上回收空间。栈保存了一个函数调用所需要的维护信息,通常由esp以及ebp两个寄存器来维护,常被称为栈帧(Stack Frame) 

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

二、函数调用中的栈帧

🔖我们在VS2013上进行观察比较方便,因为较高编译器版本底层的封装逻辑太严密,函数调用过程中的栈帧的创建是略有差异的,所以不同的编译器具体细节是取决于编译器的。

我们常常以main函数开始编写代码,调用自己写的函数,那么main函数会被其他函数调用吗?答案是有的。

为了方便查看函数栈帧调用过程的细节问题,我们直接把代码划分的足够细致。

⌨️以下用C语言代码编写:

#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;
}

🔖 我们简单写一个Add函数的代码程序,按「F10」进行调试起来,在【调试】->【窗口】->【调用堆栈】里就可以看到,(如果看不到,继续尝试往下调试),main函数是被__tmainCRTStartup函数调用的,而__tmainCRTStartup函数其实又被mainCRTStartup函数调用。

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 每个函数调用,都会为此分配一块栈空间,需要函数栈帧来维护。

那么在调用main函数之前,有一块函数栈帧空间用来维护__tmainCRTStartup的。

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

1.探究main函数栈帧的创建

接下来我们还是在【调试】->【窗口】打开反汇编,通过分析汇编指令来具体研究函数栈帧创建与销毁的逻辑。

⚠️注意:在分析汇编指令之前,最好右键取消显示符号名,不然有些代码不方便观察。

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

在观察第一行 push ebp之前,我们打开监视,先观察一下esp的值为0x008ffba8、ebp的值为0x008ffbf4

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 

🔔观察上图,第一行的 push ebp指令,进行压栈操作

📌图形展示:

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

按 「F10」调试走一步,探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

发现esp的地址减小了,由原来的0x008ffba8 变为了0x008ffba4 

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

查看内存,esp的值被修改为0x008ffbf4 说明ebp压栈成功。

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』 

🔔再次观察第二行mov ebp,esp  这条语句可以译为将esp的值给ebp,说明ebp此时应该指向esp所指向的位置。

📌图形展示:

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

不信的话,我们「F10」往下走一步,通过监视1,我们可以发现esp的值确实达到了与ebp的值相等的效果。

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔我们继续往下走 sub esp,0E4h  即将esp减去一个0E4h(0E4h,h表示HEX,十六进制的意思,实际表示的是0xe4)的值,说明esp的地址减小了,esp指向的位置就会跑向更低的地址去了。

F10继续走一步,发现esp的值确实减少了许多。

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

📌图形展示: 

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 我们可以预料到,此时esp与ebp之间的空间就是为main函数预开辟好的函数栈帧空间了。

🔔接下来,有三次压栈操作:push ebx、push esi、push edi

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔻对ebx进行压栈操作,esp栈顶指针指向了ebx

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔻对esi进行压栈操作,esp栈顶指针指向了esi

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔻对edi进行压栈操作,esp栈顶指针指向了edi

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

📌图形展示: 

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

继续往下走,

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔lea   edi,[ebp-0E4h]  lea指令的意思是Load effective address,译为加载有效地址,把ebp-0E4h的地址加载到edi中,咦?看到这里,乍一看,我们0E4h这个值怎么这么眼熟?,对,这个值在前面出现过:“esp减去了0E4h”,原来如此,ebp-0E4就是esp在三次压栈操作之前指向的位置。

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔 move ecx,39h:  将十六进制的39赋值给ecx寄存器中,这里其实表示的是39h次,这里的多少次并不是固定的,需要根据编译器确定。

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔move eax,0CCCCCCCCh: 将0xcccccccc这个十六进制的数字赋值给eax中

继续走到rep stos  这个指令,才是正儿八经的改变栈帧里的数据了,rep指令的目的是重复其上面的指令ecx的值是重复的次数。stos指令的作用是将eax中的值拷贝到edi所指向的地址处。dword:表示double word(4个字节),1个word表示2个字节。探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

以上过程完整叙述就是:将edi位置开始,向下的ecx次,也就是39h次,这么多个空间(每个空间4个字节)全部修改为eax的值,即0xCCCCCCCC

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

我们继续调试一步,观察内存中,从 0x008FFAC0 开始,一共39h*4个字节大小的空间,直到0x008FFBA4 之前,都被修改为0xcccccccc   其实为当前main函数开辟的空间都被修改为cccccccc这样的值。

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 📌图形展示:

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 ok,到此为止,为main函数开辟的栈帧空间就准备完毕了。

2.对main函数中的代码进行分析

接下来,我们正式进入对代码进行分析了~~

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 ​​🔔mov dword ptr [ebp-8],0Ahmov指令,将0Ah的值(0Ah转换十进制是10),赋给ebp-8指向的位置,此时ebp-8就是为a变量开辟的空间,值为10。(那么,我们在这里是不是就可以知道,如果局部变量没有初始化,那么它的值就是一个随机值,只不过在这里表示的是0xcccccccc),0xcccccccc如果打印成文本就是“烫烫烫”。

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 📌图形展示:

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

我们再往下调试一步,

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔mov dword ptr [ebp-14h],14h将14h(14转换成二进制是20),赋给ebp-14h指向的位置,ebp-14h指向的空间就是为变量b开辟的一块空间,值为20

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 📌图形展示:

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 🔔mov dword ptr [ebp-20h],0 :将0(0转换成二进制是0),赋给ebp-20h指向的位置,ebp-20h指向的空间就是为变量b开辟的一块空间,值为0

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 📌图形展示: 

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

到此,我们应该就明确了局部变量是怎么创建和初始化的吧~,接下来我们继续往下看, 

来到调用Add函数的部分探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔mov eax,dword ptr [ebp-14h] 又是mov指令,将ebp-14h的值,也就是b的值给到eax,鼠标悬停到eax上面,我们可以看到eax的值为0x00000014 ,eax的值就是20

🔔push eax 对eax进行压栈操作,esp往上走一步

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔mov ecx,dword ptr [ebp-8] 又是mov指令,将ebp-8的值,也就是a的值给到ecx,鼠标悬停到ecx上面,我们可以看到ecx的值为0x0000000a ,ecx的值就是10

🔔push ecx 对ecx进行压栈操作,esp再往上走一步

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

📌图形展示: 

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

走到这里的时候,想必大部分读者都会认为这是函数的传递参数吧,答案的确是的,那么后面的结果如何呢?我们继续往下看,

🔔call 00C210E1 接下来就是调用Add函数,此时需要按 「F11」键

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

调用Add函数指令之后,我们再次观察esp减少了,变成0x008ffaab 这个地址里面放进了00c21450这个值,这个值恰好是call指令下面一条指令的地址,为什么呢,其实这里就是Add函数调用结束需要回到call指令下一条继续执行,所以需要记录call下面的一条指令。

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 📌图形展示: 

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

3.探究Add函数栈帧的创建 

 继续「F11」之后,进入Add函数,此时就是准备为Add函数创建函数栈帧空间探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔push ebp对ebp进行压栈操作,把指向main函数的ebp寄存器压入栈顶

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔mov ebp,esp把esp寄存器中的值移动到ebp,此时由原来ebp指向main函数栈帧空间移动到esp指向的空间位置,

📌图形展示: 

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔sub esp,0CCh:将esp减去0CCh,esp寄存器此时再次向下增长,此时esp与ebp之间的空间就是为Add函数预开辟好的栈帧,

📌图形展示:   

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 🔔push ebx、push esi、push edi:三次压栈操作,和main函数开辟栈帧时一样,这里就不多说了,直接上图~

📌图形展示:   

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔 接下来lea指令、mov指令、rep stos指令是让Add函数的空间都初始化为0CCCCCCCC这样的值探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

📌图形展示:  

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔mov dword ptr [ebp-8],8接下来就可以给局部变量z赋予空间了,mov指令就是将0赋值给ebp-8指向的空间里,

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』 

📌图形展示:   

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 z = x + y,这个代码怎么分析呢?难道我们会再次赋予两个空间给x和y吗?其实不然,我们继续往下看

🔔mov eax,dword ptr ebp+8ebp+8空间里的值移动到eax当中去。ebp+8得到的地址值增大了,我们在图形中往下寻找,找到ebp+8指向的位置,咦,不就是我们之前将ecx寄存器进行压栈操作压入main函数栈帧上面的吗,ecx寄存器里放的就是10啊,那此时eax里面的值放的就是10

🔔add eax,dword ptr ebp+0Chebp+0Ch的值就是ebp+12,将ebp+12所指向的空间里的值,值为20加到eax寄存器中,寄存器中的值就是20了。

🔔mov dword ptr [ebp-8],eax该指令将eax的值放到ebp-8的位置,即将30赋予给局部变量Z空间里。

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

所以到这里我们知道,形参并不会在函数内部进行创建,逻辑其实是调用Add函数时,将a和b的值进行了压栈操作,然后进入到Add函数里面时,寄存器就会找到对应压栈时压的值,ebp+8、ebp+12 里的值就是a、b的一份临时拷贝,也就对应了形参x、y值。所以我们就能通透理解形参是实参的一份临时拷贝,修改形参并不会影响实参!

 📌图形展示: 

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 那么看到这里,怎么将z的值进行返回呢?我们继续往下看

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔  mov eax,dword ptr [ebp-8]这一操作指令的意思是将ebp-8空间里的值,也就是z的值,赋值给eax寄存器中,因为出函数作用域,局部变量z会被销毁!而eax寄存器中的数据是不会立马销毁。

ok,以上Add函数执行完毕,我们接下来执行返回操作了,也就是函数栈帧逐步销毁的过程了。

三、函数栈帧的销毁过程

🔔pop 出Add函数之后,有三次pop出栈操作,将edi、esi、ebx寄存器中的数据从栈顶弹出

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 📌图形展示:探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔mov esp,ebp将ebp寄存器中的值赋值到esp寄存器中,esp指向的位置就是ebp寄存器指向的位置

🔔pop ebp: ebp此时指向的位置是在为main函数开辟函数栈帧空间时压栈的ebp,在Add函数调用完毕之后,回到main函数的栈帧空间,那么main函数栈帧的栈底在哪里呢?这是对当前的ebp寄存器进行pop出栈操作,此时就返回到了main函数栈帧的栈底

🔽此时esp寄存器和ebp寄存器又正式开始维护main函数的栈帧空间

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔接下来就是ret指令 ret就是返回呀,没错,根据00C21450这个地址返回,也就是当时调用Add函数call指令的一条指令的地址,将这个地址pop一下,就回到了call指令的下一条继续执行

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

📌图形展示: 

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

🔔add esp,8:  此时是esp的地址加8,地址增大,空间减小,相当于当时形参x、y两个变量的空间由操作系统回收了,

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 🔔mov dword ptr [ebp-20h],eax: 这条指令的意思就是将eax的值赋给ebp-20h所指向的空间,我们观察图,可以看到ebp-20h不就是为局部变量c开辟的一块空间吗?c的值就是当初出Add函数作用域时,存放到eax存储器中的数据,这个值就是30!

📌图形展示: 

探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

 

这样整个Add函数销毁的过程就很清晰啦,main函数的栈帧销毁过程就不再赘述了~

我们在开头留的一些问题,通过理解函数栈帧的创建与销毁的过程,相信各位道友们,有所更清晰的认识吧~~


🤗🤗 好啦,本篇文章就到此为止啦~ 感谢大家的支持!希望对你有帮助,如有什么疑问,可以在评论区or私信告诉我~~ 🥰🥰😉文章来源地址https://www.toymoban.com/news/detail-455328.html

到了这里,关于探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • c语言(函数栈帧的创建和销毁)

    前沿:         可能很多人也是第一次听说函数栈帧这个词,想问什么是函数栈帧,理解函数栈帧有什么作用,函数栈帧的创建销毁是什么呢?这章节我们就来了解一下c语言中函数栈帧的创建和销毁。 思维导图: 目录   一、什么是函数栈帧  1.1   函数栈帧: 1.2  栈:  

    2024年02月07日
    浏览(36)
  • C语言——详解函数栈帧的创建和销毁

    为了深入学习C语言,也为了方便理解,我学习了函数栈帧。函数栈帧的创建和销毁能够让我更加深刻的了解编程逻辑和语法。我们学习语法和编程逻辑都是基于封装好的知识上得。因此,我们有必要对函数栈帧的创建和销毁进行学习。本篇博客将用来介绍函数栈帧的创建和销

    2024年02月12日
    浏览(37)
  • 【HTTP完全注解】揭开Authorization神秘的面纱

    Authorization是HTTP 提供一个用于权限控制和认证的通用框架,可能有不少小伙伴会感到疑惑\\\" Cookie不就可以做权限控制和认证吗? \\\",确实如此! Cookie确实是在单个系统内认证用户身份、保持会话状态的有效方式,但如果涉及到多个系统、多个域名或多个应用程序之间认证、授

    2024年04月25日
    浏览(32)
  • 【网络编程】揭开套接字的神秘面纱

    TCP协议: 1️⃣传输层协议 2️⃣有连接 3️⃣可靠传输 4️⃣面向 字节流 UDP协议: 1️⃣传输层协议 2️⃣无连接 3️⃣不可靠传输 4️⃣面向 数据报 我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有

    2024年02月13日
    浏览(41)
  • C语言-------函数栈帧的创建和销毁------剖析描骨

    🎂        ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂    🎂      作者介绍:                              🎂🎂        🎂 🎉🎉🎉🎉🎉🎉🎉              🎂           🎂作者id:老秦包你会,         🎂 简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂

    2024年02月14日
    浏览(33)
  • 【Linux】揭开套接字编程的神秘面纱(下)

    ​🌠 作者:@阿亮joy. 🎆 专栏: 《学会Linux》 🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 在揭开套接字编程神秘面纱(上)中,我们已经学习到了套接字编程的相关基础知识以及编写了基于 UDP 协议的

    2023年04月12日
    浏览(55)
  • 华为鸿蒙系统:揭开全新操作系统的神秘面纱

    在全球科技竞争日益激烈的背景下,我国科技巨头华为公司自主研发了一款全新的操作系统——鸿蒙。这款操作系统旨在为华为自家设备提供强大的性能、安全性和智能化特性,以满足用户不断增长的需求。为了帮助广大开发者充分挖掘鸿蒙系统的巨大潜力,华为发布了一本

    2024年02月04日
    浏览(41)
  • 揭开神秘面纱,会stream流就会大数据

    目录 准备工作 1.map类 1.1 java stream map 1.2 spark map 1.2.1 MapFunction 1.2.2 MapPartitionsFunction 2.flatMap类 2.1 java stream flatMap 2.2 spark flatMap 3 groupby类 3.1 java stream groupBy 3.2 spark groupBy 3.3 spark groupByKey 4 reduce类 4.1 java stream reduce 4.2 spark reduce 其它常见操作类 小结 如果你会任意一门语言的stream流

    2023年04月27日
    浏览(45)
  • 面试篇-揭开Spring Bean加载的神秘面纱

      启动spring容器(创建beanfactory)-加载配置(注解、xml)-实例化bean(执行构造方法)-注入依赖-初始化bean(设置属性值)-使用-销毁 解析和读取 XML 配置文件或注解配置类,获取 Bean 定义信息。 根据 Bean 定义信息实例化 Bean 对象。根据不同的作用域(如 singleton、prototype 等),S

    2023年04月17日
    浏览(45)
  • 06-揭开神秘面纱:Golang method的魅力解析

    📃个人主页:个人主页 🔥系列专栏:Golang基础 💬Go(又称Golang)是由Google开发的开源编程语言。它结合了静态类型的安全性和动态语言的灵活性,拥有高效的并发编程能力和简洁的语法。Go被设计用于构建可扩展、高性能的软件系统,具有优秀的内存管理和快速的编译速度

    2024年02月09日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包