资源描述:
《C语言函数调用方式的区别.doc》由会员上传分享,免费在线阅读,更多相关内容在工程资料-天天文库。
1、C语言函数调用方式的区别通常在使用VC进行函数定义时会指定该函数调用方式,诸如: int__stdcallmax(inta,intb) { returna>b?a:b; } int__cdeclmin(inta,intb) { returna
2、PI,CALLBACK,PASCAL。该类特点是:主调函数负责参数入栈,由函数本身负责栈的恢复。 第二类:__cdecl类别名:C/C++中默认调用方式,若你定义函数未指定函数调用约定(CallingConventions),例如在VC6中下面两个函数的调用约定是等价的: intmax(inta,intb) { returna>b?a:b; } int__cdeclmin(inta,intb) { returna
3、。 第三类:__thiscall该类比较特殊,只用于类成员函数调用,你甚至不能强制指定这个函数调用约定。它是由C/C++编译器自动添加的。在C/C++中类成员函数会默认传入一个this指针,对于此,在默入情况下,C/C++中类成员函数通过此类调用约定来指定this指针。 接着介绍一下__thiscall,__thiscall是关于类的一种调用方式。 它与其他调用方式的最大区别是: __thiscall对每个函数都增加了一个类指针参数 classaa { voidbb(intcc); }; 实际上bb的函
4、数原形是voidbb(aa&this,intcc); __cdecl的调用方式介绍:C和C++缺省调用方式 例子: voidInput(int&m,int&n);/*相当于void__cdeclInput(int&m,int&n);*/ 以下是相应的汇编代码: 00401068leaeax,[ebp-8];取[ebp-8]地址(ebp-8),存到eax 0040106Bpusheax;然后压栈 0040106Cleaecx,[ebp-4];取[ebp-4]地址(ebp-4),存到ecx 0040106Fp
5、ushecx;然后压栈 00401070call@ILT+5(Input)(0040100a);然后调用Input函数 00401075addesp,8;恢复栈 从以上调用Input函数的过程可以看出:在调用此函数之前,首先压栈ebp-8,然后压栈ebp-4,然后调用函数Input,最后Input函数调用结束后,利用esp+8恢复栈。由此可见,在C语言调用中默认的函数修饰_cdecl,由主调用函数进行参数压栈并且恢复堆栈。 下面看一下:地址ebp-8和ebp-4是什么?在VC的VIEW->debugwindows
6、->Registers,显示寄存器变量值,然后在选debugwindows->Memory,输入ebp-8的值和ebp-4的值(或直接输入ebp-8和-4),看一下这两个地址实际存储的是什么值,实际上是变量"n"的地址(ebp-8),m的地址(ebp-4)。 由此可以看出:在主调用函数中进行实参的压栈并且顺序是从右到左。另外,由于实参是相应的变量的引用,也证明实际上引用传递的是变量的地址(类似指针)。 总结:在C或C++语言调用中默认的函数修饰_cdecl,由主调用函数进行参数压栈并且恢复堆栈,实参的压栈顺序是从右到
7、左,最后由主调函数进行堆栈恢复。由于主调用函数管理堆栈,所以可以实现变参函数。另外,命名修饰方法是在函数前加一个下划线(_)。 _stdcall调用约定介绍:实际上就是PASCAL,CALLBACK,WINAPI 例子: voidWINAPIInput(int&m,int&n); 看一下相应调用的汇编代码: 00401068leaeax,[ebp-8] 0040106Bpusheax 0040106Cleaecx,[ebp-4] 0040106Fpushecx 00401070call@ILT+5(In
8、put)(0040100a) 从以上调用Input函数的过程可以看出:在调用此函数之前,首先压栈ebp-8,然后压栈ebp-4,然后调用函数Input,在调用函数Input之后,没有相应的堆栈恢复工作(为其它的函数调用,所以我没有列出)下面再列出Input函数本身的汇编代码:(实际此函数不大,但做汇编例子还是大了些