1、关于活动记录
活动记录是函数调用时用于记录一系列调用相关信息的记录,大概有如下几个内存域:
临时变量域:用来存放临时变量的值,如顺序点求值中k++的中间结果
局部变量域:用来存放函数本次执行中的局部变量;
机器状态域:用来保存调用函数之前有关于机器的状态信息、包括各种寄存器的当前值和返回地址等;
实参数据域:用于存放函数的实参信息;
返回值域:为调用者函数存放返回值;
2、一些简介
临时变量域: 之前在【C语言复习(二十八)】函数本质、顺序点 中有说到函数调用时的顺序点的问题,int k=1;f(k,k++);这条语句调用后,得到的值是2和1,那么为什么会这样呢?实际上编译器在处理k++时,有做一个临时变量:
首先生成一个临时变量,例如:int tmp;
然后把k的值赋值给tmp;
然后再计算k=k+1;
当计算完成,调用函数传递参数时,第一个要传入k的值,那么就去k的存储空间取值,因为做过k=k+1的运算,所以这时候k的值为2,第二个参数就会去tmp临时变量取值,为1;
3、参数入栈
既然函数参数的计算次序依赖于编译器的实现,那么函数参数的入栈次序又是如何的呢??比如:
int i=0,j=1;
fun(i,i+j,j+2,i+1);//值为:0,1,3,1
那么活动记录中,参数一块的内存中存放的顺序是:0,1,3,1呢?还是1,3,1,0呢?或者还是别的什么顺序??
这就要结合函数的调用约定来说明。
4、函数的调用约定
当一个函数被调用时,实参会传递给被调用的函数,而返回值会被返回给调用函数,函数的调用约定就是描述参数时怎么传递到活动记录的栈空间的,以及栈空间由谁维护。参数传递顺序:
从右到左依次入栈:__stdcall,__cdecl,__thiscall
从左到右依次入栈:__pascal,__fastcall
调用堆栈清理:
调用者清除活动记录栈空间;
被调用函数返回后,自己清除活动记录栈空间(C++构造函数与析构函数);
5、小结
函数调用是C语言的核心机制;
活动记录中保存了函数调用以及返回所需的一切信息;
调用约定是调用者和被调用者之间的调用协议,常用于不同开发者编写的库函数之间。