函数调用过程
调用函数的时候,用栈来存放函数执行所需要的参数。
而第一个进栈的使主函数中的第一条指令,然后是函数的各个参数,在大多数C的编译器里,参数是由右往左入栈的,然后是函数中的局部变量。
为什么采取从右往左入栈的顺序?
1、这样可以保证出栈时的顺序和我们函数里写的参数顺序一致
2、为了方便使用C/C++的“函数参数长度可变”的特性,举个例子,有函数printf("%d %d",1,2,3,4);如果从左边开始压栈,出栈的顺序是4,3,2,1,%d,%d,这样就还要多两个空间来存储4,3,然后再判断出4,3是不需要的,显然这样操作耗时耗空间。
约定内容
- 当参数个数多于一个的时候,按照什么什么熟悉呢把参数压入堆栈(入栈)
- 函数调用后,由谁来把堆栈恢复原状(出栈)
调用方法
C 语言: __cdecl、__stdcall、__fastcall、naked、__pascal。C++在C的基础上多出一种_thiscall。
使用的方法一般为(thiscall例外):
int _cdecl function(int a,int b);
- stdcall
C++的标准调用方式
- 参数从右向左依次入栈
- 由被调函数自己来恢复堆栈,称为自动清栈
- 函数名自动加前导下划线,后面紧跟一个@,其后再跟着参数的大小
- cdecl
(C语言缺省时的调用方式)
- 参数从右向左依次压入堆栈.
- 由调用者恢复堆栈,称为手动清栈。(由于是由调用者来挥发堆栈,所以该调用方式允许函数的参数个数不固定)
- 函数名自动加前导下划线。
- pascal
- 从左向右传递参数
- 通过EAX返回
- 堆栈由被调用者清除
- fastcall
快速调用方式,通过CPU寄存器来传递参数
- 参数以从右向左入栈
- 被调用函数清理堆栈
- thiscall
C++类成员函数缺省的调用方式,因为成员函数的调用还有一个this指针
- 参数从右向左入栈
- 如果参数个数确定,this指针通过ecx(CPU中的计数寄存器)传递给被调用者;如果参数个数不确定,this指针在所有参数压入栈后被压入栈。参数个数不定的,由调用者清理堆栈,否则由函数自己清理堆栈。可以看到,对于参数个数固定的情况,它类似于stdcall,不定时则类似于cdecl。
- naked call(不常见)