C/C++中的调用约定
在C/C++编程中,调用约定(calling conventions)是一组指定如何调用函数的规则。主要在你调用代码之外的函数(例如OS API,操作系统应用程序接口)或OS调用你(如WinMain的情况)时起作用。如果编译器不知道正确的调用约定,那么你很可能会遇到非常奇怪的崩溃,因为堆栈将无法正确管理。调用约定用于确保函数在不同平台和编译器之间正确且一致地调用。调用约定有助于标准化编译器的函数调用和参数传递方式,标准化可实现编程语言之间的互操作性。
并非所有约定都在所有支持的平台上可用,某些约定使用平台特定的实现。在大多数情况下,将忽略在特定平台上指定不支持的约定的关键字或编译器开关,并将使用平台默认约定。
调用约定通常在函数声明或定义时通过特定的关键字或属性指定。例如,在MSVC中,可以使用__cdecl、__stdcall、__fastcall等关键字来指定调用约定。在GCC中,可以使用__attribute__((cdecl))、__attribute__((stdcall))等属性来指定调用约定。在跨平台开发或调用第三方库时,需要特别注意调用约定的匹配。
C/C++中的调用约定是确定以下准则:
(1).如何将参数传递到堆栈。
(2).谁将清除堆栈,调用者还是被调用者?
(3).将使用哪些寄存器以及如何使用。
C++代码在编译阶段结束时转换为目标代码(object code)。然后我们得到目标文件(object file)。目标文件链接在一起以创建二进制文件(如exe、lib、dll)。在创建目标文件之前,我们可以告诉编译器停止并给我们.asm文件。这是将转换为目标文件的汇编文件。不同的调用约定会产生不同的汇编代码(Different calling conventions produce different assembly codes)。
MSVC支持几种函数的调用约定:"__cdecl"、"__stdcall"、"__fastcall"等,默认情况下MSVC把C语言的函数当作"__cdecl"类型,这种情况下它对该函数不进行任何符号修饰。但是一旦我们使用其它的函数调用约定时,MSVC编译器就会对符号名进行修饰,比如使用"__stdcall"调用约定的函数Add就会被修饰成"_Add@16",前面以"_"开头,后面以"@n"结尾,n表示函数调用时参数所占堆栈空间的大小。使用.def文件可以将导出函数重新命名。当一个DLL被多个语言编写的模块使用时,采用这种方法导出一个函数往往会很有用。我们经常看到Windows的API都采用"WINAPI"这种方式声明,而"WINAPI"实际上是一个被定义为"__stdcall"的宏。微软以DLL的形式提供Windows的API,而每个DLL中的导出函数又以这种"__stdcall"的方式被声明。
MSVC下不同的调用约定:使用时将以下修饰符放置在变量或者函数名称的前面,告诉编译器设置堆栈、推送参数和获取返回值的规则
1.__cdecl:C declaration,C/C++程序的默认调用约定。是一种"干净"的调用约定,不使用任何特殊指令或寄存器来传递函数参数或返回值。
(1).参数从右向左依次入栈(因此第一个参数最接近堆栈顶部)。
(2).调用者负责清理堆栈,即调用者会在返回后弹出所有参数。
(3).创建比__stdcall更大的可执行文件,因为它要求每个函数调用都包含堆栈清理代码。
(4).当调用者按照此约定清理堆栈时,我们可以为使用__cdecl调用约定的函数提供可变参数。
2.__stdcall:Standard Call,Win32 API函数使用的特定于Microsoft的调用约定。
(1).参数从右向左依次入栈(因此第一个参数最接近堆栈顶部)。
(2).被调用者(自身)负责清理堆栈,即被调用者在返回前会弹出所有参数。
3.__fastcall:在__fastcall调用约定中,如果可能的话,参数会被传递给寄存器。
(1).前两个参数(从左到右的顺序)通过寄存器ECX和EDX传递。其余参数从右向左依次入栈。
(2).被调用者负责清理堆栈。
4.__thiscall:仅适用于C++,类内方法使用的默认调用约定。
(1).参数从右向左依次入栈。
(2).this指针通过寄存器ECX传递,而不是在堆栈上传递。
(3).不能对非成员函数使用此调用约定。
(4).被调用者负责清理堆栈。
(5).__thiscall只能出现在非静态成员函数上。
在C/C++中使用调用约定的优点:
1.兼容性:不同的平台和编译器对函数参数的传递方式和返回值的返回方式可能有不同的要求。通过使用特定的调用约定,你可以确保你的代码与不同的平台和编译器兼容。
2.一致性:使用一致的调用约定有助于确保你的代码易于阅读和理解。
3.优化:某些调用约定旨在比其他调用约定更高效。例如,__fastcall调用约定可以比__cdecl或__stdcall更快,因为它使用寄存器传递函数参数。这对于经常调用的函数尤其有用。
4.安全性:使用一致的调用约定有助于防止出现诸如堆栈损坏或返回值不正确等错误。
在C/C++中使用调用约定的缺点:
1.复杂性:使用不同的调用约定会增加代码的复杂性,尤其是在处理具有许多不同功能的大型项目时。这会使代码更难理解和维护。
2.兼容性问题:如果你使用的调用约定不受特定平台或编译器支持,则可能必须修改代码或使用不同的调用约定。这可能很耗时,并且可能需要进行额外的测试以确保代码仍然正确。
3.性能开销:某些调用约定可能会带来少量性能开销,尤其是在它们需要额外的指令或寄存器使用时。这对于大多数应用程序来说可能并不重要,但对于高性能代码来说,这可能是一个考虑因素。
4.可移植性:如果你使用的调用约定特定于特定平台或编译器,则你的代码可能无法移植到其他平台或编译器。如果你想在不同平台上重用代码,或者你正在使用混合环境,这可能会成为一个问题。
注:以上整理的内容主要来自:
1. https://www.geeksforgeeks.org
2. https://www.javatpoint.com
以下为测试代码:
#include "calling_convention.hpp"
#include <iostream>namespace {#ifdef _MSC_VER
#define CDECL __cdecl
#define STDCALL __stdcall
#define FASTCALL __fastcall
#define THISCALL __thiscall
#else
#define CDECL __attribute__((cdecl))
#define STDCALL __attribute__((stdcall))
#define FASTCALL __attribute__((fastcall))
#define THISCALL __attribute__((thiscall))
#endifint CDECL add_cdecl(int a, int b) { return (a + b); }
int STDCALL add_stdcall(int a, int b) { return (a + b); }
int FASTCALL add_fastcall(int a, int b) { return (a + b); }
class Tmp {
public:int THISCALL add_thiscall(int a, int b) { return (a + b); }
};} // namespaceint test_calling_convention()
{auto ret1 = add_cdecl(1, 2);auto ret2 = add_stdcall(1, 2);auto ret3 = add_fastcall(1, 2);Tmp tmp;auto ret4 = tmp.add_thiscall(1, 2);std::cout << "results: " << ret1 << "," << ret2 << "," << ret3 << "," << ret4 << std::endl;return 0;
}
GitHub:https://github.com/fengbingchun/Messy_Test
相关文章:
C/C++中的调用约定
在C/C编程中,调用约定(calling conventions)是一组指定如何调用函数的规则。主要在你调用代码之外的函数(例如OS API,操作系统应用程序接口)或OS调用你(如WinMain的情况)时起作用。如果编译器不知道正确的调用约定,那么你很可能会遇到非常奇怪…...

微信创建小程序码 - 数量不受限制
获取小程序码:小程序码为圆图,且不受数量限制。 目录 文档 接口地址 请求方式 功能描述 注意事项 获取 scene 值 请求参数 返回参数 对接 请求方法 获取小程序码 调用获取小程序码 总结 文档 接口地址 https://api.weixin.qq.com/wxa/get…...
springboot/ssm美食分享系统Java代码web项目美食烹饪笔记分享交流
springboot/ssm美食分享系统ava美食烹饪笔记分享交流系统web美食源码 基于springboot(可改ssm)vue项目 开发语言:Java 框架:springboot/可改ssm vue JDK版本:JDK1.8(或11) 服务器:tomcat 数据库&#…...

【Redis篇】 List 列表
在 Redis 中,List 是一种非常常见的数据类型,用于表示一个有序的字符串集合。与传统的链表结构类似,Redis 的 List 支持在两端进行高效的插入和删除操作,因此非常适合实现队列(Queue)和栈(Stack…...

多级IIR滤波效果(BIQUAD),system verilog验证
MATLAB生成IIR系数 采用率1k,截止频率30hz,Matlab生成6阶对应的biquad3级系数 Verilog测试代码 // fs1khz,fc30hz initial beginreal Sig_Orig, Noise_white, Mix_sig;real fs 1000;Int T 1; //周期int N T*fs; //1s的采样点数// 数组声明…...
【WPF中ControlTemplate 与 DataTemplate之间的区别?】
前言 WPF中ControlTemplate 与 DataTemplate之间的区别? 1. 定义: ControlTemplate 是用于定义 WPF 控件的外观和结构的模板。它允许您重新定义控件的视觉表现,而不改变控件的行为。 DataTemplate 是用于定义如何呈现数据对象的模板。它通…...

Keil5配色方案修改为类似VSCode配色
1. 为什么修改Keil5配色方案 视觉习惯:如果你已经习惯了VSCode的配色方案,尤其是在使用ESP-IDF开发ESP32时,Keil5的默认配色可能会让你感到不习惯。减少视觉疲劳:Keil5的默认背景可能过于明亮,长时间使用可能会导致视…...
ndp协议简介
在IPv6中,ARP(地址解析协议)被替代为邻居发现协议(Neighbor Discovery Protocol,NDP)。NDP是IPv6网络中用于发现邻居节点(相邻设备)的协议,类似于IPv4中的ARP。但与ARP不…...

stable diffusion实践操作-大模型介绍:SD的发展历史,SD1.5和SDXL之间的差别
大家有没有这样的困惑:在找模型时,老是会出现一些奇怪的标签,像 sd1.5、sdxl 之类的模型后缀,真让人摸不着头脑,一会儿 1.0,一会儿 1.5,一会儿 XL,完全搞不清楚状况。今天就来给大家…...

系统无法运行提示:sqlsut.dll初始化错误怎么解决?多种解决方法汇总一览
遇到 sqlsut.dll 初始化错误,这通常意味着 SQL Server 的某些组件未能正确加载或初始化。以下是一些可能的解决方法汇总,旨在帮助您排查和解决问题: 解决方法 1. 检查SQL Server服务状态•确认所有相关的SQL Server服务(如SQL Se…...
通过waitress启动flask应用
假设你有一个名为 app.py 的文件,app 是指你的 Flask 应用实例。并且在这个文件中创建了一个 Flask 应用实例,那么你可以这样导入和使用它。 示例结构 假设你的项目结构如下: my_flask_app/ │ ├── app.py ├── waitress_server.py └─…...
Redis高阶之容错切换
当一台主机master宕掉之后,他的从机会取代主机么? 查看集群状态 127.0.0.1:6385> cluster nodes c8ff33e8da5fd8ef821c65974dda304d2e3327f9 192.168.58.129:638216382 slave f6b1fd5e58df90782f602b484c2011d52fc3482d 0 1733220836918 1 connecte…...

蓝桥杯准备训练(lesson2 ,c++)
3.1 字符型 char //character的缩写在键盘上可以敲出各种字符,如: a , q , , # 等,这些符号都被称为字符,字符是⽤单引号括 起来的,如: ‘a’ , ‘b’ &…...

【力扣】2094.找出3为偶数
思路 方法一:使用Set集合 1.首先是三层for循环,遍历,并且遇到不满足的情况,便跳过,继续计算。不如前导为0,以及遍历同一个数组下标的情况 2.使用Set集合来确保答案是唯一的,使用桶来标记也是可以的 3.但是…...

利用红黑树封装map,和set,实现主要功能
如果不知道红黑树是什么的时候可以去看看这个红黑树 思路 首先我们可以把封装分为两个层面理解,上层代码就是set,和map,底层就是红黑树 就相当于根据红黑树上面套了两个map,set的壳子,像下面这张图一样 对于map和set,map里面存…...

网络(TCP)
目录 TCP socket API 详解 套接字有哪些类型?socket有哪些类型? 图解TCP四次握手断开连接 图解TCP数据报结构以及三次握手(非常详细) socket缓冲区以及阻塞模式详解 再谈UDP和TCP bind(): 我们的程序中对myaddr参数是这样…...
CSS 选择器的优先级
一、基本概念 CSS 选择器的优先级决定了在样式冲突时,哪个样式规则将被应用到 HTML 元素上。通过理解 CSS 选择器的优先级,可以更好地控制网页元素的样式,避免样式冲突。 二、优先级计算规则 1. 内联样式 内联样式具有最高的优先级。 &l…...
留学生数学辅导作业随机过程高等线性代数概率论微积分优化统计
针对留学生数学辅导作业中的随机过程、高等线性代数、概率论、微积分、优化以及统计等科目,以下是一些详细的辅导建议和资源概述: 一、随机过程 概念理解: 随机过程是研究随机现象随时间演变的数学分支。它涉及概率论和数理统计的知识&#…...
移动机器人课程建图实验-ROSbug汇总
问题1描述 $ rosrun robot_state_publisher robot_state_publisher [ERROR] [1733131886.474757207]: [registerPublisher] Failed to contact master at [localhost:11311]. Retrying...解决方案 这个错误信息表明 robot_state_publisher 节点无法联系到 ROS master。通常&…...

小家电出海,沃丰科技助力保障售后服务的及时性与高效性
随着全球化步伐的加快,小家电行业也逐渐迈向国际市场,面向全球消费者提供服务。然而,跨国界的销售和服务挑战也随之而来,尤其是售后服务的及时性与高效性成为了企业亟需解决的问题。沃丰科技凭借其全渠道在线客服、工单系统和视频…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...