cdecl, stdcall, pascal,fastcall 調用約定區別

調用約定           壓參數入棧順序     把參數彈出棧者         函數修飾名 
(Calling convention) 
--------------------------------------------------------------------------------------------------------
__cdecl       右->左  被調用者    _function     微機

__cdecl       右->左  被調用者    _function     UNIX

 

 __fastcall   右->左  被調用者   @function@nnn   

   

  __stdcall   右->左  被調用者   _

function@nnn

  __pascal   左->右  被調用者  _function@nnn
   
-----------------------------------------------------------------------------------------------------------

              
    
    
  _cdecl    
   
  按至左的順序壓參數入棧調用者把參數彈出棧。對於“C”函數或者變量,修飾名是在函數名前加下劃線。對於“C++”函數,有所不同。    
   
  如函數void   test(void)的修飾名是_test;對於不屬於一個類的“C++”全局函數,修飾名是?test@@ZAXXZ。    
   
  這是缺省調用約定。由於是調用者負責把參數彈出棧,所以可以給函數定義個數不定的參數,如printf函數。    
   
   
  _stdcall    
   
  按從至左的順序壓參數入棧被調用者把參數彈出棧。對於“C”函數或者變量,修飾名以下劃線爲前綴,然後是函數名,然後是符號“@”及參數的字節數,如函數int   func(int   a,   double   b)的修飾名是_func@12。對於“C++”函數,則有所不同。    
   
  所有的Win32   API函數都遵循該約定。    

  _pascal  

   按從至右的順序壓參數入棧 ...其它的與_stdcall相同; 
    
    
  _fastcall    
   
  頭兩個DWORD類型或者佔更少字節的參數被放入ECXEDX寄存器其他剩下的參數按從右到左的順序壓入棧。由被調用者把參數彈出棧,對於“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    
   
  }     
    
        
   

 

 便於更好理解, 看下面例子(函數調用的過程以彙編代碼表示):      
    
  void   cdecl       fun1(int   x,int   y);  
  void   stdcall     fun2(int   x,int   y);  
  void   pascal     fun3(int   x,int   y);   
    

    
  ****************************************  
   
  void   cdecl       fun1(int   x,int   y);  
   
  fun1(x,y);    
   
  調用   fun1   的彙編代碼  
   
  push   y  
  push   x  
  call   fun1  
  add     sp,sizeof(x)+sizeof(y)   ;跳過參數區(x,y)  
   
  fun1   的彙編代碼:  
   
  fun1   proc    
      push   bp  
      mov     bp,sp  
      ……  
      …  
      pop     bp  
      ret ;返回,但不跳過參數區  
  fun1   endp  
   
  ****************************************  
   
  void   stdcall   fun2(int   x,int   y);  
   
  fun2(x,y);    
   
  調用   fun2   的彙編代碼  
   
  push   y  
  push   x  
  call   fun2  
   
  fun2   的彙編代碼:  
   
  fun2   proc    
      push   bp  
      mov     bp,sp  
      ……  
      …  
      pop     bp  
      ret   sizeof(x)+sizeof(y)   ;返回並跳過參數區(x,y)      
  fun2   endp  
   
  *****************************************  
   
  void   pascal     fun3(int   x,int   y);  
   
  fun3(x,y);    
   
  調用   fun3   的彙編代碼  
   
  push   x  
  push   y  
  call   fun3  
   
  fun3   的彙編代碼:  
   
  fun3   proc    
      push   bp  
      mov     bp,sp  
      ……  
      …  
      pop     bp  
      ret   sizeof(x)+sizeof(y)   ;返回並跳過參數區(x,y)      
  fun3   endp   

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章