目录
【前言】
这部分内容老师上课时不会说的哦,之所以写这篇是因为想让大家对于函数栈帧的创建和销毁这块内容有着更加深刻的理解和认识。
一、电脑存储
电脑上的存储有:硬盘、内存、寄存器
这里谈一下寄存器的概念:
寄存器是集中到CPU上的,寄存器是一块存储空间
寄存器分为:
- eax
- ebx
- ecx
- edx
- ebp
- esp
【敲黑板】:
要理解函数栈帧,就必须要理解ebp、esp这两个寄存器中存放的是地址,而且这两个地址是用来维护函数栈帧的。
二、简单例题讲解
//研究函数栈帧的创建和销毁 #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; }
【敲黑板】:
main()函数也是被其他函数调用的
醍醐灌顶-原来是这样!
<1>.局部变量是怎么创建的?
先为函数分配栈帧空间,对栈帧空间的值进行初始化,然后在栈帧里面给局部变量分配一点空间
<2>.为什么局部变量的值不初始化是随机的?
局部变量在创建之前,它们在的空间就已经有随机值了,所以局部变量不初始化值是随机值
<3>.函数是怎么传参的?传参的顺序是怎么样的?
当我们去调用函数的时候,其实在调用函数之前,我们就已经把参数从右向左开始压栈,当我们真正进入形参函数的时候,通过指针的偏移量找到了形参
<4>.形参和实参是什么关系?
形参确实是我们在压栈的时候开辟的空间,它和我们的实参只是在值上是相同的,空间却是独立的,所以形参是实参的一份临时拷贝,改变形参不会影响实参
<5>.函数调用结束后是怎么返回的?返回值是怎么带回来的?
在调用函数之前就已经将call指令的下一条地址压栈了,把调用这个函数的上一个函数的ebp存进去(压栈)了,当我们函数调用完,要返回的时候,弹出ebp,就能找到上一层函数的栈底指针往下走就能找到上一层函数的栈帧,由于我们记住了call指令的下一条指令的地址,当我们函数调用结束返回时就直接跳到call指令的下一条指令的地址处了,让我们函数调用完可以返回
三、遇见安然遇见你,不负代码不负卿!
后面会将动图补充进来的哦,那样就好理解许多啦。