转载自:http://www.cnblogs.com/lidabo/archive/2012/11/21/2781484.htmlhtml
stdcall, cdecl, pascal 区别函数
这三个参数都是告诉编译器参数的传递约定,参数的传递约定是指参数的传递顺序(从左到右仍是从右到左)和由谁来恢复堆栈指针(调用者或者是被调用者),在 Win16下有两种约定: C 和 PASCAL。 spa
C约定规定参数传递顺序是从右到左,即最右边的参数最早压栈,由调用者恢复堆栈指针。指针
PASCAL约定和C约定正好相反,它规定参数是从左向右传递,由被调用者恢复堆栈。htm
STDCALL是C约定和PASCAL约定的混合体,它规定参数的传递是从右到左, 恢复堆栈的工做交由被调用者完成。Win32只用STDCALL约定, 但除了一个特例, 即: wsprintf。blog
__stdcall 这是一种函数调用方式。 __stdcall方式函数的参数压栈顺序从右到左,是Pascal 缺省调用方式,一般用于win32 API中,本身在退出时清空栈。内存
__stdcall将参数压栈是按C语言的顺序(从右到左),但与C语言不一样的是它是由被调用者将参数从栈中清除,因此它的编译文件比_cdecl小。开发
__stdcall是Windows API函数中默认的调用约定,VB、VFP等也采用这个约定。编译器
__cdecl是C语言采用的默认调用方法,对于传送参数的内存栈倒是由调用者来维护的。实现可变参数的调用只能用该方法。是MFC的缺省调用参数。io
__fastcall方式的函数采用寄存器传递参数,VC将函数编译后会在函数名前面加上"@"前缀,在函数名后加上"@"和参数的字节数。
调用约定 压参数入栈顺序 把参数弹出栈者 函数修饰名(Calling convention)
-------------------------------------------------------------------------
__cdecl 右->左 调用者 _function
__fastcall 右->左 被调用者 @function@nnn
__stdcall 右->左 被调用者 _function@nnn
__pascal 左->右 被调用者 _function@nnn
-------------------------------------------------------------------------
以上几个关键词可在“windef.h”头文件中找到:
#define CALLBACK __stdcall
#define WINAPI __stdcall
#define WINAPIV __cdecl
#define APIENTRY WINAPI
#define APIPRIVATE __stdcall
#define PASCAL __stdcall
#define cdecl _cdecl
#ifndef CDECL#define CDECL _cdecl
#endif
几乎咱们写的每个WINDOWS API函数都是__stdcall类型的,为何??
首先,咱们谈一下二者之间的区别:WINDOWS的函数调用时须要用到栈(STACK,一种先入后出的存储结构)。当函数调用完成后,栈须要清除,这里就是问题的关键,如何清除??若是咱们的函数使用了__cdecl,那么栈的清除工做是由调用者,用COM的术语来说就是客户来完成的。这样带来了一个棘手的问题,不一样的编译器产生栈的方式不尽相同,那么调用者可否正常的完成清除工做呢?答案是不能。若是使用__stdcall,上面的问题就解决了,函数本身解决清除工做。因此,在跨(开发)平台的调用中,咱们都使用__stdcall(虽然有时是以WINAPI的样子出现)。那么为何还须要_cdecl呢?当咱们遇到这样的函数如fprintf()它的参数是可变的,不定长的,被调用者事先没法知道参数的长度,过后的清除工做也没法正常的进行,所以,这种状况咱们只能使用_cdecl。