C++中函数调用的方式

一,为什么C++的要有不同的函数调用方式
C++采用参数压栈的方式来进行函数调用:
  1. 调用者依次把参数压栈,然后调用函数。
  2. 函数被调用以后,在堆栈中取得数据,并进行计算。
  3. 函数计算结束以后,或者调用者、或者函数本身修改堆栈,使堆栈恢复原装。

因此,有这几个问题需要明确:

  1. 函数调用时参数需要以什么样的方式进行传递。对于不同的函数调用,参数的传递方式应该采取不同的方式对待,以使得其调用的效率尽可能得高。
  2. 调用结束时系统堆栈要由谁来清除。不同的编译器产生栈的方式不尽相同,那么调用者能否正常的完成清除工作呢?答案是不能。

由此,C++的函数调用方式一共分五种:
stdcall ,cdecl ,fastcall ,thiscall ,naked call

二,C++几种主要的函数传递方式:


2.1 __stdcall

__stdcall是C++最常用的参数调用方式了。也许你认为你见得还不够多,那么请看下列头文件:
#define CALLBACK PASCAL #define WINAPI CDECL #define WINAPIV CDECL #define APIENTRY WINAPI #define APIPRIVATE CDECL #ifdef _68K_ #define PASCAL __pascal .... .... #define CALLBACK __stdcall #define WINAPI __stdcall #define WINAPIV __cdecl #define APIENTRY WINAPI #define APIPRIVATE __stdcall #define PASCAL __stdcall #else #define CALLBACK #define WINAPI #define WINAPIV #define APIENTRY WINAPI #define APIPRIVATE #define PASCAL pascal #endif

其实我们通常看到的WINAPI,CALLBACK,APIENTRY 都是__stdcall的调用方式。
__stdcall调用方式具有如下特点:


__stdcall的调用方式的优点是函数自己清栈。这样上面的问题就解决了,调用方不需要帮助函数清理堆栈,调用就方便多了。在跨平台的开发或者调用中,都采用__stdcall。
2.2 _cdecl
虽然__stdcall非常强大,但是依然有它无法处理的特例。典型的,就是printf()函数。
printf是个不定长参数的函数,因此函数方无法知道参数的长度,只有调用方知道,因此函数方面无法完成堆栈的清理工作。
_cdecl调用方式具有如下特点:

参数从右向左压栈(和__stdcall一样)。 系统堆栈的清理是由调用方来完成的。 翻译的方式是函数名前自动加前导的下划线,沿用上面的例子,该函数如果为_cdecl的,将被翻译成_func。

2.3 _fastcall
这种调用方式和它的名称一样,比较快,因为它优先使用寄存器进行函数的参数调用。它的调用规则如下:

函数的第一个和第二个DWORD参数(或者尺寸更小的)通过ecx和edx传递,其他参数通过从右向左的顺序压栈。 系统堆栈由被调用方进行清理。 翻译方式类似__stdcall.

2.4 _thiscall
这种调用方式是用在类成员函数的调用的。它的特点是:

参数从右向左压栈。 如果参数是固定长的话,则函数自身清理堆栈(__stdcall),否则,则由调用方清理堆栈(类似_cdcel) 翻译方式取决参数是否定长。 2.5 naked call
这种调用方式比较少,不介绍。

参考资料:
http://blog.csdn.net/fly2k5/archive/2005/12/05/544112.aspx

你可能感兴趣的:(C++中函数调用的方式)