__stdcall约定

如果通过VC++编写的DLL欲被其他语言编写的程序调用,应将函数的调用方式声明为__stdcall方式,WINAPI都采用这种方式,而C/C++缺省的调用方式却为__cdecl。__stdcall方式与__cdecl对函数名最终生成符号的方式不同。若采用C编译方式(在C++中需将函数声明为extern "C"),__stdcall调用约定在输出函数名前面加下划线,后面加“@”符号和参数的字节数,形如_functionname@number;而__cdecl调用约定仅在输出函数名前面加下划线,形如_functionname。

  Windows编程中常见的几种函数类型声明宏都是与__stdcall和__cdecl有关的(节选自windef.h):

#define CALLBACK __stdcall //这就是传说中的回调函数

#define WINAPI __stdcall //这就是传说中的WINAPI

#define WINAPIV __cdecl

#define APIENTRY WINAPI //DllMain的入口就在这里

#define APIPRIVATE __stdcall

#define PASCAL __stdcall


  在lib.h中,应这样声明add函数:

int __stdcall add(int x, int y);


  在应用工程中函数指针类型应定义为:

typedef int(__stdcall *lpAddFun)(int, int);


  若在lib.h中将函数声明为__stdcall调用,而应用工程中仍使用typedef int (* lpAddFun)(int,int),运行时将发生错误(因为类型不匹配,在应用工程中仍然是缺省的__cdecl调用),
来源: http://www.cppblog.com/ivenher/articles/1316.html
调用约定    
   
  调用约定(Calling   convention)决定以下内容:函数参数的压栈顺序,由调用者还是被调用者把参数弹出栈,以及产生函数修饰名的方法。MFC支持以下调用约定:    
   
   
  _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    
   
  头两个DWORD类型或者占更少字节的参数被放入ECX和EDX寄存器,其他剩下的参数按从右到左的顺序压入栈。由被调用者把参数弹出栈,对于“C”函数或者变量,修饰名以“@”为前缀,然后是函数名,接着是符号“@”及参数的字节数,如函数int   func(int   a,   double   b)的修饰名是@func@12。对于“C++”函数,有所不同。    
   
  未来的编译器可能使用不同的寄存器来存放参数。    
   
   
  thiscall    
   
  仅仅应用于“C++”成员函数。this指针存放于CX寄存器,参数从右到左压栈。thiscall不是关键词,因此不能被程序员指定。    
   
   
  naked   call    
   
  采用1-4的调用约定时,如果必要的话,进入函数时编译器会产生代码来保存ESI,EDI,EBX,EBP寄存器,退出函数时则产生代码恢复这些寄存器的内容。naked   call不产生这样的代码。    
   
  naked   call不是类型修饰符,故必须和_declspec共同使用,如下:    
   
  __declspec(   naked   )   int   func(   formal_parameters   )    
   
  {    
   
  //   Function   body    
   
  }    
   
   
  过时的调用约定    
   
  原来的一些调用约定可以不再使用。它们被定义成调用约定_stdcall或者_cdecl。例如:    
   
  #define   CALLBACK   __stdcall    
   
  #define   WINAPI   __stdcall    
   
  #define   WINAPIV   __cdecl    
   
  #define   APIENTRY   WINAPI    
   
  #define   APIPRIVATE   __stdcall    
   
  #define   PASCAL   __stdcall  
来源: http://topic.csdn.net/t/20050314/17/3849920.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值