值传递和引用传递是函数参数传递的两种类型,一般而言,基本数据类型都是值传递,数组和对象采用引用传递减少对象复制开销,但也有特例。
值和引用传递本质一样
- 值传递是拷贝值到函数参数,引用传递是拷贝引用(或者对象的指针)到函数参数,把引用当成值,二者无差异。基本数据类型值传递,函数参数已经包含了值的全部信息,引用传递传地址,不包含指向的数据结构内部。
- 传递引用不止可读数据,也可改写数据,同时开销还小,这是引用传递最大的作用。联想一下CPU RIP指针或RBP/RSP指针,指哪打哪,简单直接。
不同编程语言的参数传递
对于整型、字符、枚举、浮点数等基本数据类型,都按照值传递,如下主要比较复杂类型。
- C/C++数组按引用(指针)传递,一般函数会带额外的数组大小参数。C语言struct默认按值传递,C++保持对C语言的兼容,struct和类对象默认按值传递,可以改成指针或引用。
- C#数组全部是引用传递,结构体是按值传递,可以用ref或out指示按引用传递,类对象全部是引用传递。
- Java数组和类对象都是引用传递,没有结构体。
- Ada在参数加上out修饰表明是引用传递。
值传递示例
以C语言为例,我们来研究调用一个简单的加法函数堆栈的层次。如下调用add(1, 2):
int add(int a, int b)
{
int sum;sum = a + b; return sum;
}
- 如下面图示,下划线标注的0x006FFA80/0x006FFA84是调用add函数的参数地址,分别是1和2, 方框开头是0x006FFA74, 是add函数内部形参的首地址,也对应1和2, 两个地址是独立的。
注意:在Debug版本可能不易观察,因编译器可能加入一些Debug参数,在VS2019上,有/JMC, /GS, /RTC, 它们插入了不少防范的资讯,导致堆栈信息不清晰。建议用Release版本,并关掉优化(/Od).
微风不燥,阳光正好,你就像风一样经过这里,愿你停留的片刻温暖舒心。
我是程序员小迷(致力于C、C++、Java、Kotlin、Android、iOS、Shell、JavaScript、TypeScript、Python等编程技术的技巧经验分享),若作品对您有帮助,请关注、分享、点赞、收藏、在看、喜欢,您的支持是我们为您提供帮助的最大动力。
欢迎关注。助您在编程路上越走越好!