探讨c++函数中的参数传递与返回值(一) 概念介绍与理解

本文从编译器角度,通过反汇编手段,深入的理解了1.引用的理解与使用2.结构体和类做参数时的底层实现,并对函数参数和返回值的各种情况做了归纳。希望能对大家有用,也希望大家能针对本文中的一些不足和缪误给予指正。

本文中例子均是用VS系列的VS2008编译环境下测试的。

第一章 概念介绍与理解

首先从大的方面来分,参数和返回值的传递可以分为pass by value、pass by point、pass by reference三类。


值,就是某种类型的变量在内存中的表现形式。//这么说貌似有点牵强

本文将为了方便讨论,把值分为3类:

1.      简单型值   非浮点型值的其他原生C++类型,以及任何类型的指针、引用。

2.      浮点型值   浮点型值值传递略有不同,具体的讲解,我们放到第四章。

3.      复杂型值   这里指的复杂型值,包括数组和自定义的类型(结构体和类)。

对复杂型值传递的讲解,我们放到第五章。

在C++中任何数据类型都有自己对应的指针类型,指针也是一种数据类型。指针的值是各种类型变量在内存中的地址。

引用是一种特殊的指针。引用表示一个变量的别名(此别名其实是变量的地址),对它的任何操作,本质上都是在操作它表示的变量。如取地址&,累加++,sizeof等。

其实指针和引用也是值的一种,而且可以归为本文定义的简单型值一类。但是本为为了解释传值传址传引用的区别,把这两个单独拿出来讨论。

引用

 引用的规则

(1)引用被创建的同时必须被初始化。 

(2)不能有NULL引用,引用必须与合法的存储单元关联。 
(3)一旦引用被初始化,就不能改变引用的关系。 

引用的本质

    引用类型在C++中被描述为变量的别名。实际上,C++为了简化指针操作,对指针的操作进行了封装,产生了引用类型。

实际上引用类型就是指针类型,只不过它用于存放地址的内存空间对使用者而言是隐藏的。

引用类型的存储方式和指针是一样的,都是使用内存空间存放地址值。在C++的内存体现来看,引用和指针没有分别。只是引用是通过编译器实现寻址,而指针需要手动寻址。

引用类型的参数也占内存空间,其中保存的数据是所引用数据的地址值。在反汇编下,没有引用这种数据类型。

                                                ---钱林松 《C++反汇编与逆向分析技术揭秘》

 

综上,引用在本质实现上,与指针是相同的,引用其实可以理解为是一种 TYPE* const的常指针(这样我们就可以理解为什么会规定引用的这样三条规则,当然const的约束也是编译器完成的)。

而在使用上,除了要满足引用的规则外,其他操作的操作方法和对数据的影响都与操作它所表示的变量一致。

 

引用其实可以看作是一种语法糖。

引用和指针的区别及其原因

1.引用必须被初始化,指针可以不被初始化,后期再赋值亦可。

         引用为常指针的事实,造成若不初始化,后期访问可能会出现内存访问异常。

2.不能有 NULL引用,但可以有NULL指针。

         引用为常指针的事实,造成若寸NULL引用,后期访问肯定会出现内存访问异常。

3.引用被初始化后,不可以被修改,指针可以随时更改。

引用为常指针的事实,造成不可以被修改的特性。

4.对引用的任何操作,都会被重定向到它所引用的变量,而指针则需要operator*修饰才可。

         此过程由编译器控制,编译器会把对引用初始化之后的一切操作,解释为寻址并操作其引用的变量的操作。

5.引用做函数返回值时候可以被用作左值,指针不可以。

         因为做返回值时,会是被寄存器eax返回,也就是说eax中的值是被引用或被指向变量的地址。当返回值为引用时候,对其的任何操作会被重新解释,到对其所引用的变量上。而

当返回值为指针时,对其的操作被认为是对该指针变量的操作,该指针变量在寄存器中,无法操作寄存器中值。

6.引用是类型安全的,指针不是。

     这条有待理解。


PS:有些人认为引用不能用const修饰,这是错误的观点。

int n = 10;
const int& nRef1 = n; //表示其引用的变量为常量
int const& nRef2 = n; //表示其引用的变量为常量
int& const nRef3 = n; //warning C4227: 使用了记时错误: 忽略引用上的限定符
			//表示该引用为常量,由于引用本身就不可修改,所以被忽略。
			//这种表示方法与int& nRef3 = n;完全相同。
以上三种位置的const修饰符均被编译器认可。

引用的初始化和访问

测试代码及反汇编:

	int n = 10;
0041143E  mov         dword ptr [n],0Ah 
	int& nRef = n;				//初始化引用
00411445  lea         eax,[n] 			//取变量n的地址放入eax
00411448  mov         dword ptr [nRef],eax 	//将eax中n的地址放入nRef所指示的内存单元,
//由此可见,引用其实是需要占用内存空间的,其空间内存储的是所表示变量的地址值
	nRef = 20;
0041144B  mov         eax,dword ptr [nRef] 	//将nRef中的值(地址值放入到eax
0041144E  mov         dword ptr [eax],14h 	//对eax所指空间的内容进行赋值
						//此处的操作跟指针的操作相同



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值