C/C++学习记录:深入理解三种传参方式
Posted 河边小咸鱼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C/C++学习记录:深入理解三种传参方式相关的知识,希望对你有一定的参考价值。
C/C++学习记录:深入理解三种传参方式
之前对传参这方面的东西一直是知其然不知所以然。概念用法怎么用都知道,但是其真正的内部操作流程确实是理解不足。这两天一直在总结shell脚本的笔记,写累了正好研究一下传参这方面的内容。
这篇笔记中记录了关于这方面我的理解过程和心得。关于本篇笔记的深度,也是到汇编为止不再深入,就我个人理解来看已经是足够了。
目录
一、关于三种传参方式
1. 值传参
1.1 简单总结
这是我在编程中最早接触的传参方式,也是一开始使用最多的传参方式。它的特点很明确就是简便,非常明了。当然缺点也是被说了很多次,就是慢+占用空间+不能修改实参。因为所谓的值传参是把实参的值复制了一遍,所以会有上面的特点。
1.2 我的疑问
总是说值传参的执行过程会复制实参的值,那么它的流程是怎么样的?
2. 引用传参
2.1 简单总结
这是C++里的概念,C里是没有的。它解决了值传参不能修改实参的问题,另外也比传值要快。就我目前接触到的C++代码中,里面均常常用到&
和const &
,例如stl的源码。
2.2 我的疑问
我看网上说传引用其实也是传的指针,所以一直对引用的流程很有兴趣。如果真的也是传指针,那么它的意义就是更简单明了的传指针吗?另外很多源码中都使用const &
,我一直很好奇传引用究竟能比传值快多少。
3. 指针传参
3.1 简单总结
第一次接触传指针,还是在当时学习链表的时候。在此之前,我对于指针作用的印象仅仅是文件指针和一丢丢字符串的内容,而对于学习中碰到的那些什么*p,&p
的完全没有实际应用中的感受,甚至产生了疑问,为何大伙都说指针牛p?
在接触到链表头结点的指针后,我首次发现原来传值是不能改变内容的(太菜了当时),得传指针,所以链表函数传参时,节点得取个地址传进去,由此我打开了新世界的大门,感受到了指针的牛p。以至于后面再接触java的时候感觉浑身难受,感受到了一种局限感,所以后面我决定以C/C++为方向。
对我而言,指针传参相当于是一种 “降维打击”,相当于“你收拾不了他就去找他爹收拾他”。总而言之,向下层操作性很大(提领指针的内容),可以修改实参并且速度也很快。但是,传指针相当于把传值的内容改为指针,所以指针层面也是不能被修改的(虽然我也没见过要修改最高层指针),由于指针的大小是固定的而且很小,传指针的速度也会很快。
3.2 我的疑问
底层流程是什么?是先获取地址,再走值传递那一套流程吗?
二、汇编层面剖析
1. 操作
我的理解方式是通过vs2019的反汇编功能查看低层汇编代码进行比对分析,而下面是我的操作过程。
首先是实验源码如下,可以看到我声明了三个函数,分别用了三种传参方法。
/*
* 三种传参方式测试
* 2021/8/22
*/
#include<cstdio>
//值传参
void func_value(int x)
{
x = 22;
}
//引用传参
void func_ref(int& x_ref)
{
x_ref = 2222;
}
//指针传参
void func_ptr(int* x_ptr)
{
*x_ptr = 22222;
}
int main()
{
int test_arg = 222;
//值传参
func_value(test_arg);
//引用传参
func_ref(test_arg);
//指针传参
func_ptr(&test_arg);
return 0;
}
接着,我开启调试反汇编,查看调用三个函数时的汇编源码,结果如下:
2. 总结
说实话,我没想到传引用和传指针的汇编源码竟然完全一样…而传值和另外两者的唯一区别就是第一条汇编指令。其中传值用的是汇编指令mov
,而传引用和传指针用的都是汇编指令lea
。
然后我搜了下,mov
是把内容复制到寄存器eax,而lea
是把地址复制到寄存器里。所以这里传值是把变量test_arg
的内容复制到寄存器,而后两者是把变量test_arg
的地址复制到寄存器。而内容复制一般复制量都比地址复制要大,这也就造成了效率上的差距。且传值修改的是复制的内容,所以实参不会受影响;但后两者修改的是传入指针里的内容,这两个指针(传参和实参指针)指向的内容是一致的,所以实参会收到影响。
- 所以总结下,函数传参的流程如下:
- 执行
lea
或mov
指令将内容或指针拷贝到寄存器上。 - 执行
push
指令把寄存器里的内容push进栈。 - 执行
call
指令调用函数。 - 执行
add
指令确保堆栈平衡,相当于执行pop操作把前面push的内容弹出。而add的值跟参数个数有关(之前push的值)。
三、体会
随着和C/C++打交道的时间越来越长,我探索的内容也越发深入、复杂。但是当真正理解了之前疑惑的内容,说实话还是很开心的。
另外吐槽下csdn上鱼龙混杂,发的大部分都是很基础没有营养的东西,或者不知道哪抄的错误百出的内容,当然也有很多大佬的内容让我受益匪浅(深表感谢orz),现在我搜个东西都得“发掘”半天。但是从某种意义上来讲我是有一点开心的,这说明我至少已经算入门了嘛XD
以上是关于C/C++学习记录:深入理解三种传参方式的主要内容,如果未能解决你的问题,请参考以下文章
vue2 route包含的信息和router使用的详细介绍 vue3 useRouter和useRoute 使用以及三种传参方式