C++ 子函数参数传递过程
编译环境:Visual Studio 2015
参数传递与汇编语言有很大关系。子函数传递参数主要方式有三种(这三种参数传递方式都可用用于x86汇编语言甚至其它汇编语言):
- 寄存器方式传递参数
- 存储器方式传递参数
- 堆栈方式传递参数
在C++编译时,编译器采用堆栈方式传递参数。
测试代码:
int add_num(int x, int y)
{
x++;
y++;
int sum = x + y;
cout << "add_num->x:" << (int*)&x << endl;
cout << "add_num->y:" << (int*)&y << endl;
return sum;
} int main()
{
int sum = 0;
int x = 3;
cout << "main->x:" << (int*)&x<< endl;
int y = 4;
cout << "main->y:" << (int*)&y << endl;
sum = add_num(x, y);
return 0;
}
add_num()函数反汇编代码
int add_num(int x, int y)
{
001620C0 push ebp
001620C1 mov ebp,esp
001620C3 sub esp,0CCh
001620C9 push ebx
001620CA push esi
001620CB push edi
001620CC lea edi,[ebp-0CCh]
001620D2 mov ecx,33h
001620D7 mov eax,0CCCCCCCCh
001620DC rep stos dword ptr es:[edi]
x++;
001620DE mov eax,dword ptr [x]
001620E1 add eax,1
001620E4 mov dword ptr [x],eax
y++;
001620E7 mov eax,dword ptr [y]
001620EA add eax,1
001620ED mov dword ptr [y],eax
int sum = x + y;
001620F0 mov eax,dword ptr [x]
001620F3 add eax,dword ptr [y]
001620F6 mov dword ptr [sum],eax
cout << "add_num->x:" << (int*)&x << endl;
001620F9 mov esi,esp
001620FB push offset std::endl<char,std::char_traits<char> > (01614F1h)
00162100 mov edi,esp
00162102 lea eax,[x]
00162105 push eax
00162106 push offset string "add_num->x:" (0169B30h)
0016210B mov ecx,dword ptr [_imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A (016D098h)]
00162111 push ecx
00162112 call std::operator<<<std::char_traits<char> > (0161519h)
00162117 add esp,8
0016211A mov ecx,eax
0016211C call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (016D0A4h)]
00162122 cmp edi,esp
00162124 call __RTC_CheckEsp (0161181h)
00162129 mov ecx,eax
0016212B call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (016D0ACh)]
00162131 cmp esi,esp
00162133 call __RTC_CheckEsp (0161181h)
cout << "add_num->y:" << (int*)&y << endl;
00162138 mov esi,esp
0016213A push offset std::endl<char,std::char_traits<char> > (01614F1h)
0016213F mov edi,esp
00162141 lea eax,[y]
00162144 push eax
00162145 push offset string "add_num->y:" (0169B3Ch)
0016214A mov ecx,dword ptr [_imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A (016D098h)]
00162150 push ecx
00162151 call std::operator<<<std::char_traits<char> > (0161519h)
00162156 add esp,8
00162159 mov ecx,eax
0016215B call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (016D0A4h)]
00162161 cmp edi,esp
00162163 call __RTC_CheckEsp (0161181h)
00162168 mov ecx,eax
0016216A call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (016D0ACh)]
00162170 cmp esi,esp
00162172 call __RTC_CheckEsp (0161181h)
return sum;
00162177 mov eax,dword ptr [sum] //通过eax寄存器返回计算结果
}
0016217A pop edi
0016217B pop esi
0016217C pop ebx
0016217D add esp,0CCh
00162183 cmp ebp,esp
00162185 call __RTC_CheckEsp (0161181h)
0016218A mov esp,ebp
0016218C pop ebp
0016218D ret
在函数add_num内部,x地址为0x00f8fc4c,y地址为0x00f8fc50,函数ebp地址为0x00f8fc44。

main函数反汇编代码:
int main()
{
00162270 push ebp
00162271 mov ebp,esp //保存main函数基地址0x00f8fd48
00162273 sub esp,0E8h //申请栈内存空间,栈顶地址为0x00f8fc60
00162279 push ebx
0016227A push esi
0016227B push edi
0016227C lea edi,[ebp-0E8h]
00162282 mov ecx,3Ah
00162287 mov eax,0CCCCCCCCh
0016228C rep stos dword ptr es:[edi]
0016228E mov eax,dword ptr [__security_cookie (016C004h)]
00162293 xor eax,ebp
00162295 mov dword ptr [ebp-4],eax//计算sum变量地址=ebp-4字节(前面有4次压栈)-4字节(默认变量间隔)-4字节(变量本身长度)=0x00f8fd48-12=0x00f8fd3c。
int sum = 0;
00162298 mov dword ptr [sum],0
int x = 3;
0016229F mov dword ptr [x],3 //同理 x地址= sum地址-8字节(默认变量将)-4字节(变量本身长度)=0x00f8fd30。
cout << "main->x:" << (int*)&x<< endl;
001622A6 mov esi,esp
001622A8 push offset std::endl<char,std::char_traits<char> > (01614F1h)
001622AD mov edi,esp
001622AF lea eax,[x]
001622B2 push eax
001622B3 push offset string "main->x:" (0169B50h)
001622B8 mov ecx,dword ptr [_imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A (016D098h)]
001622BE push ecx
001622BF call std::operator<<<std::char_traits<char> > (0161519h)
001622C4 add esp,8
001622C7 mov ecx,eax
001622C9 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (016D0A4h)]
001622CF cmp edi,esp
001622D1 call __RTC_CheckEsp (0161181h)
001622D6 mov ecx,eax
001622D8 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (016D0ACh)]
001622DE cmp esi,esp
001622E0 call __RTC_CheckEsp (0161181h)
int y = 4;
001622E5 mov dword ptr [y],4 //同理,y地址= x地址-8字节-4字节 = 0x00f8fd24。sum ,x ,y地址在下图显示结果一致。
cout << "main->y:" << (int*)&y << endl;
001622EC mov esi,esp
001622EE push offset std::endl<char,std::char_traits<char> > (01614F1h)
001622F3 mov edi,esp
001622F5 lea eax,[y]
001622F8 push eax
001622F9 push offset string "main->y:" (0169B5Ch)
001622FE mov ecx,dword ptr [_imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A (016D098h)]
00162304 push ecx
00162305 call std::operator<<<std::char_traits<char> > (0161519h)
0016230A add esp,8
0016230D mov ecx,eax
0016230F call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (016D0A4h)]
00162315 cmp edi,esp
00162317 call __RTC_CheckEsp (0161181h)
0016231C mov ecx,eax
0016231E call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (016D0ACh)]
00162324 cmp esi,esp
00162326 call __RTC_CheckEsp (0161181h)
sum = add_num(x, y);
0016232B mov eax,dword ptr [y]
0016232E push eax //形参y压栈
0016232F mov ecx,dword ptr [x]
00162332 push ecx //形参x压栈
00162333 call add_num (01614E7h)
00162338 add esp,8
0016233B mov dword ptr [sum],eax //将add_num函数存放在eax寄存器的计算结果赋给sum变量。
return 0;
0016233E xor eax,eax
}
main()函数ebp地址为0x00f8fd48。x地址为0x00f8fd30,且x地址中放的还是调用add_num函数之前的原始值3。y地址为0x00f8fd24,且x地址中放的还是调用add_num函数之前的原始值4。sum地址为0x00f8fd3c,该地址存放的值在调用add_num函数之后由0变为9。

流程分析:
- 变量 x,y 存放在main函数栈中。
- 调用子函数之前,将变量x,y的值在main函数栈顶压栈(参数栈)。
- 进入子函数后,将将当前栈顶地址作为子函数基地址,其中保存调用函数的基地址。
- 子函数申请内存空间。并在参数栈中执行x++,y++运行,通过寄存器eax计算x+y结果,在子函数栈内计算sum地址,并保存运行结果。
- 最后通过 eax寄存器返回子函数返回值。
结论:
- C++编译器采用堆栈方式传递参数。
- 子函数对参数的运算在参数栈上进行。在参数栈上的运算不会影响到变量x,y变量地址中存放的值。
内存运行示意图:

C++ 子函数参数传递过程的更多相关文章
- C/C++子函数参数传递,堆栈帧、堆栈参数详解
本文转载自C/C++子函数参数传递,堆栈帧.堆栈参数详解 导语 因为参数传递和汇编语言有很大联系,之后会出现较多x86汇编代码. 该文会先讲一下x86的堆栈参数传递过程,然后再分析C/C++子函数是怎 ...
- linux X64函数参数传递过程研究
基础知识 函数传参存在两种方式,一种是通过栈,一种是通过寄存器.对于x64体系结构,如果函数参数不大于6个时,使用寄存器传参,对于函数参数大于6个的函数,前六个参数使用寄存器传递,后面的使用栈传递.参 ...
- C++ 数组长度 以及 数组名作为参数传递给函数 以及 为什么不在子函数中求数组长度
在看排序,首先是插入排序,思路理清后想用代码实现,然后问题来了: 如何求数组长度? 如果没记错,在Java中应该是有直接可用的方法的, Python中(序列)也有.len,在C/C++中,字符串倒是有 ...
- windows form参数传递过程
三.windows form参数传递过程 在Windows 程序设计中参数的传递,同样也是非常的重要的. 这里主要是通过带有参数的构造函数来实现的, 说明:Form1为主窗体,包含控件:文本框text ...
- shell 脚本之获取命令输出字符串以及函数参数传递
在ubuntu 14.04之后,所有的U盘挂载也分用户之分,最近很多操作也和U盘有关,所以就研究了一上午shell脚本函数以及字符串操作的方法. 字符串操作: 获取他的命令输出比较简单,打个简单的比方 ...
- 函数可重入问题reentrant functions(函数执行过程中可以被中断,允许多个副本)
最近经常听到这个名词,以前也听到过,不过接触更多的是“线程安全问题”,而且本人也一直理解的是两个名字的含义是一样的.今天仔细总结一下这个名词相关的概念. 引用博文:可重入函数和不可重入函数 (http ...
- VB几种函数参数传递方法,Variant,数组,Optional,ParamArray
VB几种函数参数传递方法,Variant,数组,Optional,ParamArray 一) 过程的参数被缺省为具有 Variant 数据类型. 1)ByRef按 地址传递参数在 VB 中是缺省的 按 ...
- (转)C#在父窗口中调用子窗口的过程(无法访问已释放的对象)
C#在父窗口中调用子窗口的过程: 1. 创建子窗口对象 2. 显示子窗口对象 笔者的程序中,主窗体MainFrm通过菜单调用子窗口ChildFrm.在窗体中定义了子窗口对象,然后在菜单项点击事件中 ...
- PL/SQL --> 动态SQL调用包中函数或过程
动态SQL主要是用于针对不同的条件或查询任务来生成不同的SQL语句.最常用的方法是直接使用EXECUTE IMMEDIATE来执行动态SQL语句字符串或字符串变量.但是对于系统自定义的包或用户自定的包 ...
随机推荐
- 如何利用Python实现Office在线预览
目前,市场对于Office在线预览功能的需求是很大的.对于我们用户本身来说,下载Office文件后再实现预览是极其不方便的,何况还有一些不能打开的专业文档.压缩文件等.此时,能提供在线预览服务的软件就 ...
- 用C++创建Https客户端,用Mingw编译
- [c++]关于指针的一些问题记录
const char* 和char* 之间的转换 const char*是指向常量的指针,而不是指针本身为常量,可以不被初始化.该指针可以指向常量也可以指向变量,只是从该指针的角度而言,它所指向的是常 ...
- CS5265 demoboard|CS5265测试板电路参考|CS5265 Typec转HDMI 4K60HZ方案
CS5265是TYPEC转HDMI2.0音视频转换芯片,CS5265符合DP1.4协议,且输出的视频信号是HDMI2.0 即4K60HZ CS5265集成了DP1.4兼容接收机和HDMI2.0b兼容 ...
- Java EE数据持久化框架 • 【第2章 MyBatis实现DML操作】
全部章节 >>>> 本章目录 2.1 标签 2.1.1 标签简单应用 2.1.2 使用JDBC方式返回主键自增的值 2.1.3 使用标签返回普通主键的值 2.1.4 实践练 ...
- STM32零基础入门教程
本文主要是针对想了解STM32,手里又没有太多预算的小伙伴.市场上针对新手来说,比较合适的STM32开发版太贵,比如正点原子.树莓派等,便宜的教程又不详细,这对想白嫖的小伙伴来说不太有好,所以我选了一 ...
- redis-ha手动切换slave节点为master
仅做个人记录,请慎重参考!! 问题描述:使用redis-ha启动了3个pod,现在还有一个pod正常运行,并且为slave(理论上第一个起来的pod应该为master) 通过info命令查看下图 尝试 ...
- K210,yolo,face_mask口罩检测模型训练及其在K210,kd233上部署
前段时间考研,再加上工作,时间很紧,一直没有更新博客,这几天在搞k210的目标检测模型,做个记录,遇到问题可以添加qq522414928或添加微信13473465975,共同学习 首先附上github ...
- 实验 2 :Mininet 实验 —— 拓扑的命令脚本
实验2: Mininet 实验--拓扑的命令脚本 一.实验目的 掌握 Mininet 的自定义拓扑生成方法:命令行创建.Python 脚本编写 二 .实验任务 通过使用命令行创建.Python 脚本编 ...
- 新增访客数量MR统计之Reduce和Runner相关准备
关注公众号:分享电脑学习回复"百度云盘" 可以免费获取所有学习文档的代码(不定期更新)云盘目录说明:tools目录是安装包res 目录是每一个课件对应的代码和资源等doc 目录是一 ...