C/C++函数调用约定:__cdecl、__stdcall、__fastcall和__thiscall

目录

1.引言

2.常见函数调用约定

2.1.__cdecl

2.2.__stdcall

2.3.__fastcall

2.4.__thiscall

3.几种调用约定比较

4.注意事项


1.引言

        在C和C++编程中,函数调用约定(Calling Convention)定义了函数如何接收参数、如何返回值以及由谁来清理栈上的参数。不同的平台和编译器可能会支持不同的调用约定。在Windows平台上,尤其是在使用Microsoft的编译器(如MSVC)时,常见的调用约定包括__cdecl__stdcall__fastcall__thiscall。

        对于一个基本函数 int func(int a, int b);,C++ 底层通过帧栈来描述函数调用的过程,一个帧栈过程大致包含了以下过程:

  • 栈空间的开辟,也叫栈拉伸。

  • 调用子函数参数准备,这个过程会把子函数需要的参数压栈。

  • 寄存器现场保护,跳转调用子函数。

  • 栈空间回收,也叫栈平衡。

  在这些过程中,每种编译器实现不同,导致了同一段函数调用得到的汇编代码也不相同。参数按照什么顺序压栈?调用完成后由谁负责清理压栈的参数?为了统一这些行为,于是又了函数调用约定。

2.常见函数调用约定

2.1.__cdecl

__cdecl 是 C/C++ 默认的调用约定,声明函数是不加任何调用约定的限制会默认采用 __cdecl 调用约定。该调用约定有以下特点:

  • 按从右至左的顺序压参数入栈。

  • 由调用者把参数弹出栈。切记:对于传送参数的内存栈是由调用者来维护的,返回值在 EAX 中。因此对于像 printf 这样可变参数的函数必须用这种约定。

  • 编译器在编译这种调用规则的函数时,生成修饰名在输出函数名前加上一个下划线前缀,格式为 _function。如函数 int add(int a, int b) 的修饰名是 _add

测试代码如下:

#include <iostream>int __cdecl test(int x, int y, int s, int t)
{return x + y + s + t;
}int main()
{int a = 1; // 断点test(1, 2, 3, 4);return 0;
}

显示反汇编得到下面结果:

  • 参数从右向左进行压栈,先压栈 2,再压栈 1。push 压栈的时候就进行了栈拉伸,这里是 8 个字节。

  • 在 test 函数调用完成后,调用者也就是 main 函数中进行了栈平衡。

2.2.__stdcall

__stdcall 是微软规定的 C++ 标准调用方式,__stdcall 通常用于 Win32 API 中,具有如下特点:

  • 按从右至左的顺序压参数入栈。

  • 由被调用者(callee)负责清理栈上的参数。切记:函数自己在退出时清空堆栈,返回值在EAX中。

  • __stdcall 调用约定在输出函数名前加上一个下划线前缀,后面加上一个 @ 符号和其参数的字节数,格式为 _function@number。如函数int sub(int a, int b)的修饰名是 _sub@8。

测试代码如下:

#include <iostream>int __stdcall test(int x, int y, int s, int t)
{return x + y + s + t;
}int main()
{int a = 1; // 断点test(1, 2, 3, 4);return 0;
}

显示反汇编得到下面结果:

  • 在 main 函数中进行参数压栈时,参数从右往左进行压栈。push 压栈的时候就进行了栈拉伸,这里是 8 个字节。

  • 在 test 函数调用结束后,main 函数中没有进行栈平衡操作。

  • 在 test 函数返回时,通过 ret 8 实现了栈平衡,也就是被调用者负责栈平衡。

2.3.__fastcall

__fastcall 调用约定按照名字理解应该更快一些,这是由于它是用的寄存器传递参数,相对于内存而言,寄存器的读写速度更快,该调用约定有以下特点:

  • __fastcall 用 ECX 和 EDX 传送前两个 DWORD 或更小的参数,剩下的参数仍自右向左压栈传递。

  • 由被调用者把参数弹出栈。

  • __fastcall 调用约定在输出函数名前加上一个 @ 符号,后面也是一个 @ 符号和其参数的字节数,格式为 @function@number,如 int sub(int a, int b) 的修饰名是 @sub@8。

测试代码如下:

#include <iostream>int __fastcall test(int x, int y, int s, int t)
{return x + y + s + t;
}int main()
{int a = 1; // 断点test(1, 2, 3, 4);return 0;
}

显示反汇编得到下面结果:

  • 参数压栈时,前两个参数通过寄存器传递,第三个参数开始进行压栈,同样是从右向左。

  • 在 test 函数调用结束后,main 函数中没有进行栈平衡操作。

  • 在 test 函数返回时,通过 ret 8 实现了栈平衡,也就是被调用者负责栈平衡。

2.4.__thiscall

__thiscall 是 x86 架构上类的非可变参数成员函数的默认调用约定,具有以下特点:

  • 按从右至左的顺序压参数入栈。

  • this 指针通过寄存器 ECX 传递,而不是在堆栈上传递。

  • 由被调用者把参数弹出栈。

  当成员函数是不定参数的情况下,采用 __cdecl 调用约定,所有参数都会被压栈,this 指针最后被压栈。

3.几种调用约定比较

调用约定参数传递方式清理栈方符号修饰使用场合
__cdecl从右到左调用者清理_functionnameC/C++默认调用约定
__stdcall从右到左被调用者清理_functionname@paramsizeWin API
__fastcall从右到左被调用者清理@functionname@paramsize调用速度快
__thiscall从右到左被调用者清理\成员函数非不定参数

4.注意事项

  • 调用约定影响函数的链接和调用方式,因此在定义和声明函数时,调用约定必须一致。
  • 在跨语言或跨编译器调用函数时,需要特别注意调用约定的匹配,以避免潜在的崩溃或数据损坏。
  • 在64位系统上,许多调用约定之间的差异变得不那么重要,因为所有的参数通常都通过寄存器传递(例如,Windows上的__vectorcall)。

        理解这些调用约定对于深入理解和优化Windows平台上的C/C++代码非常重要。另外值得注意的是上面的调用约定是针对 x86 架构,在 x64、arm64 这样的架构上有更多的寄存器用来传递参数,实际的情况又会和上面不同了。

推荐阅读:

从汇编来角度剖析C语言函数调用过程_如何用汇编实现函数调用-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/454441.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【小沐学Golang】基于Go语言搭建静态文件服务器

文章目录 1、简介2、安装2.1 安装版2.2 压缩版 3、基本操作3.1 go run3.2 go build3.3 go install3.4 go env3.5 go module 4、文件服务器4.1 filebrowser4.2 gohttpserver4.3 goFile 5、FAQ5.1 go.mod 为空5.2 超时 结语 1、简介 https://golang.google.cn/ Go语言诞生于2007…

word表格跨页后自动生成的顶部横线【去除方法】

Hello World! Its been a long time. 这一年重心放在了科研、做事、追寻新的经历上&#xff0c;事有正事、琐事、幸事、哀事&#xff0c;内心与认知成长了一些&#xff0c;思想成熟了几分&#xff0c;技艺也有若干收获。不管怎样&#xff0c;来打个卡吧&#xff0c;纪念一下&…

Web前端高级工程师培训:使用 Node.js 构建一个 Web 服务端程序(3)

11、HTTP 协议 11-1、协议的定义 HTTP 是一种能够获取如 HTML 这样的网络资源的 protocol(通讯协议)。它是在 Web 上进行数据交换的基础&#xff0c;是一种 client-server 协议&#xff0c;也就是说&#xff0c;请求通常是由像浏览器这样的接受方发起的。一个完整的Web文档通…

Tailwind Starter Kit 一款极简的前端快速启动模板

Tailwind Starter Kit 是基于TailwindCSS实现的一款开源的、使用简单的极简模板扩展。会用Tailwincss就可以快速入手使用。Tailwind Starter Kit 是免费开源的。它不会在原始的TailwindCSS框架中更改或添加任何CSS。它具有多个HTML元素&#xff0c;并附带了ReactJS、Vue和Angul…

Docker安装Mysql5.7,解决无法访问DockerHub问题

Docker安装Mysql5.7&#xff0c;解决无法访问DockerHub问题 简介 Docker Hub 无法访问&#xff0c;应用安装失败&#xff0c;镜像拉取超时的解决方案。 摘要 &#xff1a; 当 Docker Hub 无法访问时&#xff0c;可以通过配置国内镜像加速来解决应用安装失败和镜像拉取超时的…

使用爬虫爬取Python中文开发者社区基础教程的数据

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

微信小程序文本收起展开

这里写自定义目录标题 微信小程序文本收起展开常见问题的梯形背景框 微信小程序文本收起展开 参考 https://juejin.cn/post/6963904955262435336 <!-- 常见问题解答 --><view classcontentBottom><view classBottomFirst><text id0 data-id0 class&quo…

python + mitmproxy 爬手机app (1)

起因&#xff0c; 目的: 想爬手机上某鱼。 mitmproxy 简介: 一句话: mitmproxy 就是中间人攻击. (只不过&#xff0c; 你安装&#xff0c;就代表你愿意承担风险。)源码&#xff1a;https://github.com/mitmproxy/mitmproxy文档: https://mitmproxy.org/ 安装过程: 见聊天记…

eCAP超声波测距-ePWM电机调速

目录 eCAP超声波测距 整体框架 关键模块 实验效果 PWM电机调速 DRV8833基本介绍 整体框架 eCAP超声波测距 本实验所用的超声波HC-SR04模块如下图所示&#xff0c;左边为正面图&#xff0c;右边为反面图。 HC-SR04基本工作原理&#xff1a; &#xff08;1&#xff09;采…

spring源码中的,函数式接口,注解@FunctionalInterface

调用方 /org/springframework/beans/factory/support/AbstractBeanFactory.java:333sharedInstance getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It mi…

Kafka之消费者客户端

1、历史上的二个版本 与生产者客户端一样&#xff0c;在Kafka的发展过程当中&#xff0c;消费者客户端主要有两个大的版本&#xff1a; 旧消费者客户端&#xff08;Old Consumer&#xff09;&#xff1a;基于Scala语言开发的版本&#xff0c;又称为Scala消费者客户端。新消费…

rpm 命令

rpm&#xff08;Red Hat Package Manager&#xff09;是 Red Hat Linux 及其衍生发行版&#xff08;如 CentOS、Fedora&#xff09;中用于管理软件包的系统。它允许用户安装、卸载、升级、查询和验证软件包。 一、安装软件包 &#xff08;1&#xff09;安装一个 RPM 软件包&a…

高并发下如何保证接口的幂等性?

前言 接口幂等性问题,对于开发人员来说,是一个跟语言无关的公共问题。本文分享了一些解决这类问题非常实用的办法,绝大部分内容我在项目中实践过的,给有需要的小伙伴一个参考。 不知道你有没有遇到过这些场景: 有时我们在填写某些form表单时,保存按钮不小心快速点了两次…

十二、【智能体】深入剖析:大模型节点的全面解读,举例说明,教你如何在扣子中嵌入代码

大模型节点 大模型节点主要分为5部分&#xff1a; 处理类型 单次批处理 模型类型&#xff1a;目前可以选择的模型有 豆包、通义千问、智谱、MinMax和Kimi输入:此时的参数可以被下面的提示词所用提示词&#xff1a;给大模型使用的提示词输出&#xff1a;经过此大模型处理后的输…

Vehicle Spy3.9如何新建工程—总览

1&#xff1a;写作目的 学习和精通SPY的使用&#xff0c;对于spy&#xff0c;目前主要是通用系用的比较多&#xff0c;本身spy的生产厂家英特佩斯也是美国的公司&#xff0c;除了软件自带教程。中文网上很少能找到相关的中文教程。 故写下这篇文章&#xff0c;帮助自己和大家…

Ubuntu(22.04)本地部署Appsmith

Ubuntu&#xff08;22.04&#xff09;安装Appsmith 简要介绍 Appsmith 是一个开源的低代码开发平台&#xff0c;旨在帮助开发者和非开发者快速构建定制化的内部应用程序和管理工具。通过直观的拖拽界面和丰富的预配置组件&#xff0c;Appsmith 让用户无需编写大量代码即可创建…

软件工程的学习之详细绪论

软件的定义 软件是程序和所有使程序正确运行所需要的相关文档和配置信息。 Software Program Data Document 一、软件危机&#xff1a; 软件开发和维护过程中遇到的一系列严重问题。 二、具体表现&#xff1a; 1、产品不符合用户的实际需要&#xff1b; 2、软件开发生产率…

Sigrity 共模电感的S-parameter仿真数据导入

下载S4P参数 https://ds.murata.co.jp/simsurfing/cmcc.html?partnumbers%5B%22DLW32MH101XT2%22%5D&oripartnumbers%5B%22DLW32MH101XT2L%22%5D&rgearjomoqke&rgearinfocom&md51729525489334# 下载S4P参数&#xff1b; DLW32MH101XT2.s4p Sigrity 使用-dif…

Mac电脑:资源库Library里找不到WebServer问题的解决

今天看到一本书里写到Windows电脑自带IIS Web服务器&#xff0c;好奇了一下下&#xff0c;mac电脑自带的又是什么服务器呢&#xff1f;经查询&#xff0c;原来是Apache服务器&#xff0c;这个名字我很熟悉。只是如何设置呢&#xff1f;我从来没用过&#xff0c;于是试验了一番。…

如何看待AI技术的应用前景?

人工智能&#xff1a;引领未来的变革力量 在当今快速变化的科技时代&#xff0c;人工智能&#xff08;AI&#xff09;作为一项前沿技术&#xff0c;已然成为推动全球各行各业变革的核心驱动力。随着人工智能技术的不断发展&#xff0c;其广泛的应用前景和深远的影响力&#xf…