当前位置: 首页 > news >正文

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编程中&#xff0c;调用约定(calling conventions)是一组指定如何调用函数的规则。主要在你调用代码之外的函数(例如OS API&#xff0c;操作系统应用程序接口)或OS调用你(如WinMain的情况)时起作用。如果编译器不知道正确的调用约定&#xff0c;那么你很可能会遇到非常奇怪…...

微信创建小程序码 - 数量不受限制

获取小程序码&#xff1a;小程序码为圆图&#xff0c;且不受数量限制。 目录 文档 接口地址 请求方式 功能描述 注意事项 获取 scene 值 请求参数 返回参数 对接 请求方法 获取小程序码 调用获取小程序码 总结 文档 接口地址 https://api.weixin.qq.com/wxa/get…...

springboot/ssm美食分享系统Java代码web项目美食烹饪笔记分享交流

springboot/ssm美食分享系统ava美食烹饪笔记分享交流系统web美食源码 基于springboot(可改ssm)vue项目 开发语言&#xff1a;Java 框架&#xff1a;springboot/可改ssm vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#…...

【Redis篇】 List 列表

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

多级IIR滤波效果(BIQUAD),system verilog验证

MATLAB生成IIR系数 采用率1k&#xff0c;截止频率30hz&#xff0c;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之间的区别&#xff1f; 1. 定义&#xff1a; ControlTemplate 是用于定义 WPF 控件的外观和结构的模板。它允许您重新定义控件的视觉表现&#xff0c;而不改变控件的行为。 DataTemplate 是用于定义如何呈现数据对象的模板。它通…...

Keil5配色方案修改为类似VSCode配色

1. 为什么修改Keil5配色方案 视觉习惯&#xff1a;如果你已经习惯了VSCode的配色方案&#xff0c;尤其是在使用ESP-IDF开发ESP32时&#xff0c;Keil5的默认配色可能会让你感到不习惯。减少视觉疲劳&#xff1a;Keil5的默认背景可能过于明亮&#xff0c;长时间使用可能会导致视…...

ndp协议简介

在IPv6中&#xff0c;ARP&#xff08;地址解析协议&#xff09;被替代为邻居发现协议&#xff08;Neighbor Discovery Protocol&#xff0c;NDP&#xff09;。NDP是IPv6网络中用于发现邻居节点&#xff08;相邻设备&#xff09;的协议&#xff0c;类似于IPv4中的ARP。但与ARP不…...

stable diffusion实践操作-大模型介绍:SD的发展历史,SD1.5和SDXL之间的差别

大家有没有这样的困惑&#xff1a;在找模型时&#xff0c;老是会出现一些奇怪的标签&#xff0c;像 sd1.5、sdxl 之类的模型后缀&#xff0c;真让人摸不着头脑&#xff0c;一会儿 1.0&#xff0c;一会儿 1.5&#xff0c;一会儿 XL&#xff0c;完全搞不清楚状况。今天就来给大家…...

系统无法运行提示:sqlsut.dll初始化错误怎么解决?多种解决方法汇总一览

遇到 sqlsut.dll 初始化错误&#xff0c;这通常意味着 SQL Server 的某些组件未能正确加载或初始化。以下是一些可能的解决方法汇总&#xff0c;旨在帮助您排查和解决问题&#xff1a; 解决方法 1. 检查SQL Server服务状态•确认所有相关的SQL Server服务&#xff08;如SQL Se…...

通过waitress启动flask应用

假设你有一个名为 app.py 的文件&#xff0c;app 是指你的 Flask 应用实例。并且在这个文件中创建了一个 Flask 应用实例&#xff0c;那么你可以这样导入和使用它。 示例结构 假设你的项目结构如下&#xff1a; my_flask_app/ │ ├── app.py ├── waitress_server.py └─…...

Redis高阶之容错切换

当一台主机master宕掉之后&#xff0c;他的从机会取代主机么&#xff1f; 查看集群状态 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的缩写在键盘上可以敲出各种字符&#xff0c;如&#xff1a; a &#xff0c; q &#xff0c; &#xff0c; # 等&#xff0c;这些符号都被称为字符&#xff0c;字符是⽤单引号括 起来的&#xff0c;如&#xff1a; ‘a’ &#xff0c; ‘b’ &…...

【力扣】2094.找出3为偶数

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

利用红黑树封装map,和set,实现主要功能

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

网络(TCP)

目录 TCP socket API 详解 套接字有哪些类型&#xff1f;socket有哪些类型&#xff1f; 图解TCP四次握手断开连接 图解TCP数据报结构以及三次握手&#xff08;非常详细&#xff09; socket缓冲区以及阻塞模式详解 再谈UDP和TCP bind(): 我们的程序中对myaddr参数是这样…...

CSS 选择器的优先级

一、基本概念 CSS 选择器的优先级决定了在样式冲突时&#xff0c;哪个样式规则将被应用到 HTML 元素上。通过理解 CSS 选择器的优先级&#xff0c;可以更好地控制网页元素的样式&#xff0c;避免样式冲突。 二、优先级计算规则 1. 内联样式 内联样式具有最高的优先级。 &l…...

留学生数学辅导作业随机过程高等线性代数概率论微积分优化统计

针对留学生数学辅导作业中的随机过程、高等线性代数、概率论、微积分、优化以及统计等科目&#xff0c;以下是一些详细的辅导建议和资源概述&#xff1a; 一、随机过程 概念理解&#xff1a; 随机过程是研究随机现象随时间演变的数学分支。它涉及概率论和数理统计的知识&#…...

移动机器人课程建图实验-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。通常&…...

小家电出海,沃丰科技助力保障售后服务的及时性与高效性

随着全球化步伐的加快&#xff0c;小家电行业也逐渐迈向国际市场&#xff0c;面向全球消费者提供服务。然而&#xff0c;跨国界的销售和服务挑战也随之而来&#xff0c;尤其是售后服务的及时性与高效性成为了企业亟需解决的问题。沃丰科技凭借其全渠道在线客服、工单系统和视频…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

C#中的CLR属性、依赖属性与附加属性

CLR属性的主要特征 封装性&#xff1a; 隐藏字段的实现细节 提供对字段的受控访问 访问控制&#xff1a; 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性&#xff1a; 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑&#xff1a; 可以…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

Web中间件--tomcat学习

Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机&#xff0c;它可以执行Java字节码。Java虚拟机是Java平台的一部分&#xff0c;Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

Unity VR/MR开发-VR开发与传统3D开发的差异

视频讲解链接&#xff1a;【XR马斯维】VR/MR开发与传统3D开发的差异【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...