函数参数约定、传递顺序、传递方式

本文详细解读了cdecl、stdcall、fastcall、thiscall和clrcall等各种C/C++调用约定在参数传递上的特点,包括从左到右和从右到左的求值顺序,以及值传递、引用传递和指针传递的优劣。特别强调了结构和类传递时的安全隐患及效率提升策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参数约定 

传递方式

简要说明

编译约定

cdecl

C调用约定,参数从右到左求值并入栈,调用函数清理堆栈;实现可变参数的函数(如printf)只能使用该调用约定

C: _resize

C++:

?resize@@YA*@Z

thiscall

C++ 成员函数调用约定,this指针存放于ECX寄存器中,参数从右到左求值入栈,被调函数在退出时清理堆栈

stdcall

Windows API的缺省调用方式,参数以值传递方式从右到左求值入栈,被调函数在退出时清理堆栈

C:_resize@4

C++:

?resize@@YG*@Z

fastcall

前两个参数是DWORD类型或更小的数据则传入ECX、EDX,其它参数以从右到左的方式求值入栈,被调函数退出时清理堆栈

C:@resize@4

C++:

?resize@@YI*@Z

clrcall

从左到右加载参数到CLR expression stack

与thiscall 合用

pascal

不再使用

参见 stdcall

syscall

不再使用

fortran

不再使用

【注】VC++对函数的省缺声明是"__cedcl",将只能被C/C++调用,C++调用约定中的符号(*)需要根据参数填充;

参数传递顺序

参数传递顺序有从左到右传递从右到左传递两种,由于参数也是一个表达式,关注参数的求值顺序对写出正确的程序非常关键,例如:calc (origin++, origin+inc),如果不清楚参数表达式求值顺序就无法正确理解程序;

概念名称

简要说明

备注(案例)

从左到右传递

对函数的多个输入参数从左到右求值并压入栈

入栈为在堆栈中分配内存

出栈为释放参数所占内存

从右到左传递

对函数的多个输入参数从右到左求值并压入栈

参数传递方式:

参数传递方式有值传递引用传递指针传递三种,三种参数本质上都是【值传递】,基本类型由于地址所指即为真实数据,传递时会生成真实数据的拷贝,将会消耗更多的堆栈内存,而引用传递和指针传递乃间接指向对象,传递时只是生成地址的拷贝,堆栈内存消耗比较少;我们首先对各个概念做一个简要回顾:

概念名称

简要说明

备注(案例)

值传递

对参数求值后把其所指数据生成一份拷贝再压入栈

堆栈内存消耗大户

引用传递

对参数求值后把它的引用地址压入栈

平台字节宽度,例如32位占4字节,64位占8字节。

指针传递

对参数求值后把它的引用地址压入栈

参数如何传递才最安全、最有效率?

Windows平台的调用栈空间是在链接时固定分配并写入二进制文件,UNIX类平台则可以通过环境变量设置,他们的默认栈初始空间情况如下:

平台

默认堆栈

最大堆栈

说明

SunOS/Solaris

8192KB

无上限

可通过环境变量配置

Unix/Linux

8192KB

???

Windows

x86/x64

1024KB

32768K

链接时修改

Itanium

4096KB

32768K

cygwin

2048KB

???

指针传递、引用传递都是传递对象的地址,传给函数时都是把这个地址压入栈,32位平台为四个字节,64位平台为八个字节。标量类型、指针、引用等数据类型长度都小于等于机器字长,占用的空间小,入栈、出栈速度都是非常块的,一般情况下默认栈空间足够使用,不会出现堆栈溢出的问题;

但结构、类的值传递方式带来诸多问题,例如堆栈溢出、数据丢失、效率低下等,建议结构、类完全使用指针或者引用传递;如:

安全隐患

简要说明

备注

堆栈溢出

如果结构和类都是很大,创建其副本会消耗大量的空间和时间,最终产生溢出错误

数据丢失

类对象创建副本时,会受到类实现的影响而无法完全复制,参见文档《Effective C++》第二章

效率降低

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值