C语言三种函数调用约定_cdecl与_stdcall及_fastcall详细讲解

 更新时间:2022年10月19日 14:47:46   作者:是星星鸭  
本篇文章使用的工具是vs2010,内容可能涉及到汇编的知识,建议有一些汇编基础的再来看,不过没有汇编基础也没有关系,了解一下这三种调用约定即可

C语言常用的调用约定

以下就是C语言常用的三种调用约定:

调用约定参数压栈顺序平衡堆栈
__cdecl从右往左依次入栈调用者清理堆栈
__stdcall从右往左依次入栈自身清理堆栈
__fastcallECX/EDX传递前两个参数 剩下的从右往左依次入栈自身清理堆栈

下面会举例为大家讲解三种调用约定的区别。

一、_cdecl调用约定

这是C语言默认的调用约定,使用的平栈方式为外平栈

示例代码:

以下代码不使用任何调用约定,让我们来看看函数默认的调用约定是什么。

#include <stdio.h>
int method(int x,int y)
{
    return x+y;
}
int main()
{
    __asm mov eax,eax;    // 此处设置断点
    method(1,2);
    return 0;
}

编译、调试、ALT+8调出反汇编如下:

根据上面这张图的描述,默认的约定很符合__cdecl约定。

使用cdecl约定,如下:

vs2010:Ctrl+Alt+F7重新生成、F5调试、ALT+8查看反汇编:

一模一样,可以看出__cdecl就是C语言默认的调用约定。

二、_stdcall调用约定

和__cdecl一样都是从右往左入栈参数,不过该调用约定使用的平栈方式是内平栈

示例代码:

Ctrl+Alt+F7重新生成、F5调试、ALT+8查看反汇编:

可以看到,这里已经看不到堆栈的处理了。

F11不断执行,直到进入call指令调用的method函数中:

平栈操作跑到函数内部了,__cdecl约定是调用者(main)函数进行平栈,而__stdcall约定是函数内部自身进行平栈。

三、_fastcall调用约定

这是一个比较特殊的调用约定,当函数参数为两个或者以下时,该约定的效率远远大于上面两种,当然随着参数越来越多,该约定与上面两种约定的差距逐渐缩小。

证明如下:

首先,我们使用__fastcall调用约定并传入两个参数。

重新生成、调试、汇编:

F11进入函数内部查看:

可以看出函数内部和外部都没有清理堆栈的操作。

这也就是__fastcall效率高的原因。

因为寄存器就是属于cpu的,然后堆栈是内存,使用cpu进行操作的效率肯定会大于使用内存,所以我们使用寄存器的效率肯定比push传参效率高很多啊。

那么为什么没有平栈操作呢?

因为我们没有使用堆栈啊,我们只是用了寄存器,并没有使用堆栈操作。

但是当我们传入更多的参数的时候就需要用到堆栈了,因为__fastcall他只给我们提供了两个寄存器ECX/EDX可以用来传参。

四个参数试试:

重新生成、调试、汇编:

F11进入函数内部查看:

通过四个参数的传递,证明了:

函数参数除了前两个参数使用寄存器、其他的依旧使用堆栈从右往左传参,并且是自身清理堆栈,不是调用者清理。

思考为什么参数越来越多的时候,__fastcall与其他调用约定的差距越来越小呢?

答:首先我们知道了使用寄存器(cpu)的效率远远大于使用堆栈(内存),然而__fastcall约定也只能使用两个寄存器,当函数参数只有两个时,__fastcall可以完全使用寄存器进行函数传参,所以这个时候他和__cdecl和__stdcall的差距最大。随着参数越来越多,__fastcall依旧只能使用两个寄存器,这样一来参数越多,__fastcall使用内存的占比就越大,所以性能差距也就越来越小。

总结

以上的内容汇总如下:

调用约定参数压栈顺序平衡堆栈调用约定特点
__cdecl从右往左依次入栈调用者清理堆栈这是C语言默认的调用约定,使用的平栈方式为外平栈
__stdcall从右往左依次入栈自身清理堆栈和__cdecl一样都是从右往左入栈参数,不过该调用约定使用的平栈方式是内平栈
__fastcallECX/EDX传递前两个参数 剩下的从右往左依次入栈自身清理堆栈这是一个比较特殊的调用约定,当函数参数为两个或者以下时,该约定的效率远远大于上面两种,当然随着参数越来越多,该约定与上面两种约定的差距逐渐缩小。

到此这篇关于C语言三种函数调用约定_cdecl与_stdcall及_fastcall详细讲解的文章就介绍到这了,更多相关C语言函数调用约定内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • c++中的bind使用方法

    c++中的bind使用方法

    bind是这样一种机制,它可以预先把指定可调用实体的某些参数绑定到已有的变量,产生一个新的可调用实体,这种机制在回调函数的使用过程中也颇为有用。接下来通过本文给大家介绍c++中的bind使用方法,感兴趣的朋友一起看看吧
    2022-01-01
  • C++超详细讲解强制类型转换

    C++超详细讲解强制类型转换

    在C++语言中新增了四个关键字static_cast、const_cast、reinterpret_cast和dynamic_cast。这四个关键字都是用于强制类型转换的
    2022-05-05
  • C语言使用回溯法解旅行售货员问题与图的m着色问题

    C语言使用回溯法解旅行售货员问题与图的m着色问题

    回溯法即是在按条件搜索走不通的情况下退回再选择其他路线的方法,这里我们来看C语言使用回溯法解旅行售货员问题与图的m着色问题的方法示例:
    2016-07-07
  • C++基于对话框的程序的框架实例

    C++基于对话框的程序的框架实例

    这篇文章主要介绍了C++基于对话框的程序的框架,以实例形式讲述了C++对话框程序框架,有助于深入理解基于C++的Windows程序设计,需要的朋友可以参考下
    2014-10-10
  • Linux下控制(统计)文件的生成的C代码实现

    Linux下控制(统计)文件的生成的C代码实现

    这篇文章主要介绍了Linux下控制(统计)文件的生成的C代码实现,感兴趣的小伙伴们可以参考一下
    2016-01-01
  • C++实现简单走迷宫的代码

    C++实现简单走迷宫的代码

    这篇文章主要为大家详细介绍了C++实现简单走迷宫的代码,利用回溯法求解,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • Qt+Live555搭建RTSP服务器的方法步骤

    Qt+Live555搭建RTSP服务器的方法步骤

    本文主要介绍了Qt+Live555搭建RTSP服务器的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • C/C++ MD5算法的实现代码

    C/C++ MD5算法的实现代码

    下面就将网上有关MD5算法一些知识整理一下,方面自己查阅,需要的朋友可以参考下
    2017-07-07
  • 详解C语言读取文件求某一列的平均值

    详解C语言读取文件求某一列的平均值

    本文粗浅比较了C语言中常用的几种读取文件的函数的效率,并给出了几段求取某列平均值的代码,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多度进步
    2022-02-02
  • C++中explict关键字用法

    C++中explict关键字用法

    这篇文章主要介绍了C++中explict关键字用法的相关资料,本文介绍的非常详细,具有参考借鉴价值,感兴趣的朋友一起学习吧
    2016-05-05

最新评论