C++中函数调用的方式

来源:互联网 发布:ubuntu启动wifi 编辑:程序博客网 时间:2024/05/17 23:41
一,为什么C++的要有不同的函数调用方式
C++采用参数压栈的方式来进行函数调用:
  1. 调用者依次把参数压栈,然后调用函数。
  2. 函数被调用以后,在堆栈中取得数据,并进行计算。
  3. 函数计算结束以后,或者调用者、或者函数本身修改堆栈,使堆栈恢复原装。

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

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

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

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


    2.1 __stdcall

    __stdcall是C++最常用的参数调用方式了。也许你认为你见得还不够多,那么请看下列头文件:

    其实我们通常看到的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
  • 原创粉丝点击