cdecl、pascal、stdcall、fastcall

简介: Directive Parameter order   Clean-up Passes parameters in registers?register   Left-to-right         Routine        Yespascal    Left-to-right        ...

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

调用约定           压参数入栈顺序     把参数弹出栈者         函数修饰名 
(Calling convention) 
--------------------------------------------------------------------------------------------------------
__cdecl                 右->左             调用者                                 _function     
__fastcall             右->左              被调用者                           @function@nnn      
__stdcall             右->左               被调用者                           _function@nnn
__pascal             左->右               被调用者                           _function@nnn
    
-----------------------------------------------------------------------------------------------------------

__cdecl是C/C++和MFC程序默认使用的调用约定,也可以在函数声明时加上__cdecl关键字来手工指定。采用__cdecl约定时,函数参数按照从右到左的顺序入栈,并且由调用函数者把参数弹出栈以清理堆栈。因此,实现可变参数的函数只能使用该调用约定。由于每一个使用__cdecl约定的函数都要包含清理堆栈的代码,所以产生的可执行文件大小会比较大。__cdecl可以写成_cdecl。
         __stdcall调用约定用于调用Win32 API函数。采用__stdcal约定时,函数参数按照从右到左的顺序入栈,被调用的函数在返回前清理传送参数的栈,函数参数个数固定。由于函数体本身知道传进来的参数个数,因此被调用的函数可以在返回前用一条ret n指令直接清理传递参数的堆栈。__stdcall可以写成_stdcall。
         __fastcall约定用于对性能要求非常高的场合。__fastcall约定将函数的从左边开始的两个大小不大于4个字节(DWORD)的参数分别放在ECX和EDX寄存器,其余的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的堆栈。__fastcall可以写成_fastcall。 
·特别说明
1. 在默认情况下,采用__cdecl方式,因此可以省略.
2. WINAPI一般用于修饰动态链接库中导出函数
3. CALLBACK仅用于修饰回调函数

便于更好理解, 看下面例子(函数调用的过程以汇编代码表示):      
    
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  

目录
相关文章
|
1月前
|
编译器 Linux C语言
C/C++ 常见函数调用约定(__stdcall,__cdecl,__fastcall等):介绍常见函数调用约定的基本概念、用途和作用
C/C++ 常见函数调用约定(__stdcall,__cdecl,__fastcall等):介绍常见函数调用约定的基本概念、用途和作用
23 0
|
8月前
2023-2-19-什么是‘constexpr‘
2023-2-19-什么是‘constexpr‘
31 0
|
编译器 程序员 API
函数调用约定:__stdcall、__cdecl和__fastcall介绍
函数调用约定:__stdcall、__cdecl和__fastcall介绍
117 0
|
C语言 C++ 编译器
|
程序员
我的第一次Pascal程序
今天刚刚来学点Pascal语言,都怪我买的书大多是用Pascal语言写的,所以我只能试着学一点咯! 来一段程序员最经典的Hello World!   1 program exl_2; 2 begin 3 write('Hello World!'); 4 end.
778 0