在C语言中,函数是个很重要的概念,平时写代码也会经常用到函数,可是在调用一个函数时在内存中是怎样实现的呢,下来这篇文章就谈谈函数在内存中的调用过程。
函数运行的环境—栈帧
首先要引入的一个概念叫栈帧
,从逻辑上讲,栈帧就是一个函数执行的环境:函数参数、函数的局部变量、函数执行完后返回到哪里等等。
栈帧
的地址是由高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部(低地址)。
这里又提到了两个关键的寄存器:ebp
和esp
。
ebp
:指向栈帧底部的寄存器
ebp
:指向栈帧顶部的寄存器
如图:
下面通给过一段简单的代码来解释一下函数的调用过程:
#include<stdio.h>
int Add(int x, int y)
{
int z;
z = x + y;
return z;
}
int main()
{
int a, b, c;
a = 1;
b = 2;
c = Add(a, b);
printf("%d\n", c);
return 0;
}
在这段代码中,在main函数中调用了Add函数来计算两个数的和并返回。
下来在VS中对这段函数进行反汇编:
这是main函数的调用过程,在分配好ebp和esp指针后,先将main函数内所有内存全部刷成
0xcccccccc,这也是如果不给局部变量定义就会出现随机值的原因。
下面再看Add函数的调用
1、移动ebp、esp形成新的栈帧结构。
2、压栈(push)形成临时变量并执行相关操作。
3、return一个值。
在调用完成之后,esp和ebp指针要回到之前的位置
1、出栈(pop)。
2、回复main函数的栈帧结构。(pop )
3、返回main函数
到这儿,函数的整个调用过程就结束了,这就是函数调用时在栈帧中的动作。