zoukankan      html  css  js  c++  java
  • cdecl、pascal、stdcall、fastcall

    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  

  • 相关阅读:
    51nod 1445 变色DNA ( Bellman-Ford算法求单源最短路径)
    51nod 1307 绳子与重物 (标记父节点更新即可)
    AOJ GRL_1_C: All Pairs Shortest Path (Floyd-Warshall算法求任意两点间的最短路径)(Bellman-Ford算法判断负圈)
    AOJ GRL_1_B: Shortest Path
    AOJ GRL_1_A: Single Source Shortest Path (Dijktra算法求单源最短路径,邻接表)
    【算法】prim算法(最小生成树)(与Dijkstra算法的比较)
    【算法】Dijkstra算法(单源最短路径问题)(路径还原) 邻接矩阵和邻接表实现
    【算法】Bellman-Ford算法(单源最短路径问题)(判断负圈)
    面试之二:Redis是单线程还是多线程?以及处理模型。
    面试之一:CMS收集器整理
  • 原文地址:https://www.cnblogs.com/lidabo/p/3274706.html
Copyright © 2011-2022 走看看