原文:C/C++ 函数参数和返回值传递机制
作者:Breaker <breaker.zy_AT_gmail>
说明 C/C++ 函数调用中,参数和返回值传递的机制,包括低级汇编指令和高级 C++ 对象拷贝构造
关键字:参数传递,返回值传递,按值传递 (passed by value),按引用传递 (passed by reference),拷贝构造
相关参考
目录
函数调用栈示意图
调用顺序 func_1->func_2,调用时栈操作顺序从 高地址 到 低地址
示意图如下:
栈示意图后面的 1、2 表示哪个函数会访问这些存储
基本过程如此,但编译器之间略有差别,如 VC 调试方式编译,用 sub esp, XXh 预留栈空间等
C++ 中参数和返回值传递都是初始化语义
prolog 和 epilog
- prolog: 进入 func_2 时的准备工作,保存 func_1 的环境,如 EBP 和其它寄存器值,预留栈空间等
- epilog: 离开 func_2 时的恢复工作,恢复 func_1 的环境
prolog 和 epilog 由编译器产生,但可使用 VC 的 __declspec(naked) 裸函数,手工编写 prolog 和 epilog,参考 MSDNConsiderations for Writing Prolog/Epilog Code
参数按值传递
以按值传递一个 POD 结构 Student 为例,说明汇编指令
编译器 Linux GCC 4
编译命令 g++ -O0 -g3 -Wall
测试程序:
IDA 调试 POD 参数传递
call print_student 指令及栈操作
print_student prolog 及栈操作
IDA 中两个函数参数相关汇编符号:
- var_XX: caller 访问 callee 的参数使用的符号,表示为:相对于 caller ESP+XXh 的偏移量 [ESP+XXh+var_XX]
- arg_XX: callee 访问自己参数使用的符号,表示为:相对于 callee EBP 的偏移量 [EBP+arg_XX]
在一次函数调用中,var_XX 和 arg_XX 是同一存储的不同名称,在 caller 中用 var_XX 访问,在 callee 中用 arg_XX 访问
C++ 对象参数传递
传递 C++ 类对象时的拷贝构造,以及按引用传递、按地址(指针)传递参数时的汇编指令
编译器 VC 2010
编译命令 cl /Od /MDd /Zi /EHsc (Debug)
测试程序:
VC 调试 C++ 对象参数传递
下面是 caller 中调用 some_func() 的汇编指令:
-
按引用传递 和 按地址(指针)传递
两者的汇编指令相似:
-
按值传递 double 字面量
-
按值传递 Complex 对象
调用 Complex copy ctor 拷贝构造对象:
-
调用 some_func()
堆栈数据
返回值按值传递
测试程序:
返回值传递步骤
-
callee 用返回对象 ret_obj 初始化 class TestClass 的 返回值临时对象
临时对象的销毁时机
参考 "The C++ Programming Language"
临时对象在维持它的那条语句之后被销毁,除非临时对象被约束到其它名字,此时由这个名字控制临时对象的生存期,约束不产生初始化或赋值语义,没有拷贝
-
callee 返回时,由 ret_obj 的存储方式,决定是否销毁
如果 ret_obj 是局部对象或 callee 参数,则在返回时销毁
-
caller 中根据对 callee 返回值的使用,会有不同的情况,常见如下:
返回值传递测试结果
对上面程序的测试结果
返回值传递效率
-
因为拷贝开销,一般 不建议返回对象,除非:
- 返回值是内部类型,如 整数、浮点数、枚举、指针、数组名等
- 返回值是小 size 类型的对象,如 Point、Rect 等 POD,或 smart pointer 等小型封装类
-
返回引用类型实际是 caller 直接访问 callee 中返回值对象的别名,没有拷贝开销
-
返回局部变量时,可使用 返回时构造 技巧,如:
return 语句中的 Complex(2.3, 1.2) 即是返回值临时对象,不调用 copy ctor 创建第 2 个临时对象,返回时没有销毁局部对象的开销
分享到:
相关推荐
函数参数与函数调用 1、函数调用的作用: ·用实参数向形式参数传递数据; ·为获得数据参数及在函数体中声明的变量分配存储空间; ·中断现行(调用)函数,把流程向被调用函数的入口处,开始执行被调...
函数参数与函数调用 1、函数调用的作用: ·用实参数向形式参数传递数据; ·为获得数据参数及在函数体中声明的变量分配存储空间; ·中断现行(调用)函数,把流程向被调用函数的入口处,开始执行被调...
也许你从书上了解到了C++的函数参数和返回值类型有类对象,引用,指针。 但是却不知道在内存中到底是怎么回事。本文档从内存堆栈分别揭示了这6种情况下到底在这个过程中发生了什么事情。
NDK开发时,C/C++调用Java的函数的一些案例; 传递int类型参数: https://blog.csdn.net/niuba123456/article/details/80978500 传递String类型参数: https://blog.csdn.net/niuba123456/article/details/80978916 ...
c#调用C++动态库、执行回调函数,并回传结构体参数数据。vs2017环境编写C#和C++动态库,这个为完整工程例子,可供相关人员学习参考。
完整的C++调用Python脚本源码,包含参数传递和函数返回值处理等,且解决传递中文参数出现乱码等问题
golang调用c++DLL返回值为char*参数为const char*,读取返回DLL返回值,传递char*型参数
第8 章 C++函数的高级特性 8.1 函数重载的概念. 8.2 成员函数的重载、覆盖与隐藏. 8.3 参数的缺省值. 8.4 运算符重载. 8.5 函数内联. 8.6 一些心得体会. 第9 章 类的构造函数、析构函数与赋值函数 9.1 构造函数与析...
remote-function底层使用命令管道进行通讯,内置的流程完成了函数参数和返回值的序列化过程。且大部分的参数和返回值都可以使用内置的(反)序列化方法,对于一些复杂的数据类型,需要自己(反)序列化。 项目首页...
1. 函数参数,默认调用惯例情况下从右向左的顺序依次把参数压入栈中 2. 函数的返回地址,即调用方调用此函数(如call func1)的下一条指令的地址 3.
第8章 C++函数的高级特性 8.1 函数重载的概念 8.2 成员函数的重载、覆盖与隐藏 8.3 参数的缺省值 8.4 运算符重载 8.5 函数内联 8.6 一些心得体会 第9章 类的构造函数、析构函数与赋值函数 9.1 构造函数与析构函数的...
06函数返回值为指针类型;07数组和指针;08指针数组;09多级指针) 9.结构体(01typedef语句;02结构体定义和使用;03结构体数组;04结构体数组排序;05结构体赋值;06结构体嵌套;07共用体) 10.位运算(01位运算;...
将“引用”作为函数返回值类型的格式、好处和需要遵守的规则? 格式:类型标识符 &函数名(形参列表及类型说明){ //函数体 } 好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个...
如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”,由于“指向指针的指针”这个概念不容易理解,我们也可以用函数返回值来传递动态内存。 常常有人把return语句用错了。这里强调不要用return语句...
C++源于C语言。 1970年,两位程序员Brian Kernighan和Dennis Ritchie首创了一种新的程序设计语言,取名...函数、参数传递与函数返回值 函数名重载与操作符重载 动态存储分配 友元函数与内联函数 结构、联合与类
《高质量C/C++编程指南》,作者:林锐,pdf 格式,大小 327KB。 目录: 前 言 ..................................................................................................................................
7. C中可变参数函数实现 38 8. C程序内存中组成部分 41 9. C编程拾粹 42 10. C语言中实现数组的动态增长 44 11. C语言中的位运算 46 12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 64 15. ...
7. C中可变参数函数实现 38 8. C程序内存中组成部分 41 9. C编程拾粹 42 10. C语言中实现数组的动态增长 44 11. C语言中的位运算 46 12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 64 15. ...
如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。 为什么要使用回调函数? 因为可以把调用者与被调用者分开。调用者不关心谁是被调用者,所有它...
7. C中可变参数函数实现 38 8. C程序内存中组成部分 41 9. C编程拾粹 42 10. C语言中实现数组的动态增长 44 11. C语言中的位运算 46 12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 64 15. ...