_stdcall 与 _cdecl

_stdcall 与 _cdecl  

 

       几乎我们写的每一个WINDOWS API函数都是__stdcall类型的,首先,需要了解两者之间的区别: WINDOWS的函数调用时需要用到栈(STACK,一种先入后出的存储结构)。当函数调用完成后,栈需要清除,这里就是问题的关键,如何清除??

        如果我们的函数使用了_cdecl,那么栈的清除工作是由调用者,用COM的术语来讲就是客户来完成的。这样带来了一个棘手的问题,不同的编译器产生栈的方式不尽相同,那么调用者能否正常的完成清除工作呢?答案是不能。

        如果使用__stdcall,上面的问题就解决了,函数自己解决清除工作。所以,在跨(开发)平台的调用中,我们都使用__stdcall(虽然有时是以WINAPI的样子出现)。

        那么为什么还需要_cdecl呢?当我们遇到这样的函数如fprintf()它的参数是可变的,不定长的,被调用者事先无法知道参数的长度,事后的清除工作也无法正常的进行,因此,这种情况我们只能使用_cdecl。到这里我们有一个结论,如果你的程序中没有涉及可变参数,最好使用__stdcall关键字。

函数声明后面加个stdcall是什么意思
     在Win32汇编中,我们经常要和API打交道,另外也会常常使用自己编制的类似于API的带参数的子程序,本文要讲述的是在子程序调用的过程中进行参数传递的概念和分析。一般在程序中,参数的传递是通过堆栈进行的,也就是说,调用者把要传递给子程序(或者被调用者)的参数压入堆栈,子程序在堆栈取出相应的值再使用,比如说,如果你要调用 SubRouting(Var1,Var2,Var3),编译后的最终代码可是      
  push   Var3   
  push   Var2   
  push   Var1   
  call   SubRouting   
  add   esp,12   
    
      也就是说,调用者首先把参数压入堆栈,然后调用子程序,在完成后,由于堆栈中先前压入的数不再有用,调用者或者被调用者必须有一方把堆栈指针修正到调用前的状态。参数是最右边的先入堆栈还是最左边的先入堆栈、还有由调用者还是被调用者来修正堆栈都必须有个约定,不然就会产生不正确的结果,而Stdcall就是参数从右到左压入栈,由被调用的子程序来修正堆栈的指针。
Directive Parameter   order Clean-up Passes   parameters   in   registers?   
  register Left-to-right Routine Yes   
  pascal Left-to-right Routine No   
  cdecl Right-to-left Caller No   
  stdcall Right-to-left Routine No   
  safecall Right-to-left Routine No 
 
 
请问__stdcall是什么意思啊,怎样使用呢。
网友回答:
发表者:yjh1982

msdn

发表者:zfbt

_stdcall是一种函数调用习惯!说明函数的参数是从右往左进栈的!   
  用法:放在函数声明前

发表者:sevencat

而且好像是调用者自己清stack的

发表者:dancingcalf

  
  看msdn中有关vc的函数调用修饰词解说的

发表者:sevencat

int   func(int   x)   
  int   func(int   x,...)   
  不知道我有没有记错。   
  前一个各种调用方式都可以。   
  而后一个只能用c调用方式,因为被调用函数并不知道调用者向stack里面压了多少参数。

发表者:harmonious

调用约定     
        
  调用约定(calling   convention)决定以下内容:函数参数的压栈顺序,由调用者还是被     
  调用者把参数弹出栈,以及产生函数修饰名的方法。mfc支持以下调用约定:     
        
        
  1、_cdecl     
        
  按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于“c”函数或者变量,修饰     
  名是在函数名前加下划线。对于“c++”函数,有所不同。     
        
  如函数void   test(void)的修饰名是_test;对于不属于一个类的“c++”全局函数,修饰     
  名是?test@@zaxxz。     
        
  这是mfc缺省调用约定。由于是调用者负责把参数弹出栈,所以可以给函数定义个数不定     
  的参数,如printf函数。     
        
        
  2、_stdcall     
        
  按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。对于“c”函数或者变量,修     
  饰名以下划线为前缀,然后是函数名,然后是符号“@”及参数的字节数,如函数int   f     
  unc(int   a,   double   b)的修饰名是_func@12。对于“c++”函数,则有所不同。所有的w     
  in32   api函数都遵循该约定。     
        
  3、_fastcall     
        
  头两个dword类型或者占更少字节的参数被放入ecx和edx寄存器,其他剩下的参数按从右     
  到左的顺序压入栈。由被调用者把参数弹出栈,对于“c”函数或者变量,修饰名以“@    
  ”为前缀,然后是函数名,接着是符号“@”及参数的字节数,如函数int   func(int   a,     
    double   b)的修饰名是@func@12。对于“c++”函数,有所不同。未来的编译器可能使用     
  不同的寄存器来存放参数。     
        
  4、thiscall     
        
  仅仅应用于“c++”成员函数。this指针存放于cx寄存器,参数从右到左压栈。thiscal     
  l不是关键词,因此不能被程序员指定。     
        
        
  5、naked   call     
        
  采用1-4的调用约定时,如果必要的话,进入函数时编译器会产生代码来保存esi,edi,     
  ebx,ebp寄存器,退出函数时则产生代码恢复这些寄存器的内容。naked   call不产生这 样的代码。     
        
  naked   call不是类型修饰符,故必须和_declspec共同使用,如下:     
        
  __declspec(   naked   )   int   func(   formal_parameters   )     
  {     
  //   function   body     
  }     
        
  在mfc中有以下宏定义:     
        
  #define   callback   __stdcall     
  #define   winapi   __stdcall     
  #define   winapiv   __cdecl     
  #define   apientry   winapi     
  #define   apiprivate   __stdcall     
  #define   pascal   __stdcall

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值