cdecl、stdcall、fastcall、declspec 的用法和区别

首先这三个修饰符是c和c++调用约定 

调用约定(Calling convention)决定以下内容:函数参数的压栈顺序,由调用者还是被调用者把参数弹出栈,以及产生函数修饰名的 方法 。MFC支持以下调用约定:     
    

__cdecl,__stdcal和__fastcalll都是函数调用规范,规定了参数出入栈的顺序和方法,如果只用VC 编程 的话可以不用关心,但是要在C++和Pascal等其他语言通信的时候就要注意了,只有用相同的方法才能够调用成功.另外,像printf这样 接受 可变个数参数的函数只有用cdecl才能够实现.   

_cdecl 

按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于“C”函数或者变量,修饰名是在函数名前加下划线。对于“C++”函数,有所不同。 

如函数void test(void)的修饰名是_test;对于不属于一个类的“C++”全局函数,修饰名是?test@@ZAXXZ。 

这是MFC缺省调用约定。由于是调用者负责把参数弹出栈,所以可以给函数定义个数不定的参数,如printf函数。 


_stdcall 

按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。对于“C”函数或者变量,修饰名以下划线为前缀,然后是函数名,然后是符号“@”及参数的字节数,如函数int func(int a, double b)的修饰名是_func@12。对于“C++”函数,则有所不同。 

所有的Win32 API函数都遵循该约定。


_ fastcall  

是把函数参数列表的前三个参数放入寄存器eax,edx,ecx,其他参数压栈。 fastcall是BCB为了更好的兼容Delphi写的VCL而用的,delphi中的默认call是fastcall,是把函数参数列表的前三个参数放入寄存器。

举个例子,其实就是在函数声明的时候多加一个关键字,比如很多API函数就是象这样声明的: 
int WINAPI MessageBoxA(HWND,LPCSTR,LPSTR,UINT); 
而WINAPI实际上就是__stdcall. 
大多数API都采用__stdcall调用规范,这是因为几乎所有的 语言 都支持__stdcall调用.相比之下,__cdecl只有在C语言中才能用.但是__cdecl调用有一个特点,就是能够 实现 可变参数的函数调用,比如printf,这用__stdcall调用是不可能的. 
__fastcall这种调用规范比较少见,但是在Borland C++ Builder中比较多的采用了这种调用方式. 
如果有共享代码的 需要 ,比如写DLL,推荐的方法是用__stdcall调用,因为这样适用范围最广.如果是C++语言写的代码供Delphi这样的语言调用就必须声明为__stdcall,因为Pascal不支持cdecl调用(或许Delphi的最新版本能够支持也说不定,这个我不太清楚).在其他一些地方,比如写COM组件,几乎都用的是stdcall调用.在VC或Delphi或C++Builder里面都可以从项目设置中更改默认的函数调用规范,当然你也可以在函数声明的时候加入__stdcall,__cdecl,__fastcall关键字来明确的指示本函数用哪种调用规范.  

__declspec主要是用于说明DLL的引出函数的,在某些情况下用__declspec(dllexport)在DLL中生命引出函数,比用传统的DEF文件方便一些.在普通 程序 中也可以用__declspec(dllimport)说明函数是位于另一个DLL中的导出函数.   


http://hi.baidu.com/guqiwei/blog/item/6b56f413848394075aaf53f2.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值