本部分内容旨在帮助学习C语言函数部分理解更加深刻
一.困惑内容:
1.局部变量是怎样创建的
2.为什么局部变量是随机值
3.函数是怎么传参的,传参的顺序是怎样的
4.形参和实参是什么关系
5.函数调用是怎么做的
6.函数调用是结束后怎么返回的
不同编译器下会有差异,本案例以vs2013为例
1.什么是函数栈帧
每一个函数调用,都要在栈区创建一个空间
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);
}
如该代码中,main函数就是一次函数调用,在调用main函数时会在栈区开辟一块空间,该空间称为main函数的函数栈帧。
2.寄存器
(压栈push:给栈顶放一个元素 出栈pop:从栈顶删除一个元素)
计算机中存在寄存器:eax,ebx,ecx,edx,ebp,esp。而ebp,esp这两个寄存器中存放的是地址,这两个地址是用来维护函数栈帧的。
2.1 怎样来维护函数栈帧
ebp栈底指针,esp栈顶指针,调用哪个函数,寄存器就在维护哪个函数。他俩之间的空间就是这次调用的函数栈帧。
1.在vs2013中,main函数也是被其他函数调用的(__tmainCRTStartup),该函数被mainCRTStarup调用,在调用main函数时,要先进行压栈指令(push),将ebp压到esp。
2.之后执行mov指令,将ebp的指向esp的地址。
3.再执行sub指令,改变esp指向的地址,两个寄存器中间的空间,就是给main函数开辟的空间。
4.然后在顶上zz的执行三次压栈push,将ebx,esi,edi三个值压进去。
5.再执z行加载指令(lea),将一个有效地址加载到edi中,然后将下边的四字节数字全部初始化(为main函数开辟的空间)成cc cc cc cc。
6.将a的值放在ebp-8处,如果未初始化,随机值的产生来自于函数函数栈帧中的cc cc cc cc。
7.执行call指令,将函数下面的指令保存。
8.在将两个值从右向左压栈到顶上(传参)。
9.再执行创建Add函数的函数栈帧。
10.在还没有传参时,就将两个参数压栈到栈顶(形参是实参的一份临时拷贝),使用时直接调用。
因为临时拷贝到栈顶,所以形参的改变不影响实参。
11.经过计算后,将z的值放在eax当中,因为出了函数之后,函数会销毁。
12.然后执行出栈(pop),将函数调用销毁。移动ebp,esp。
13.最后执行ret指令,回到call的下一条指令继续执行。.