首先,我在网上搜索了下C++指针和引用的区别,得到的结果大致如下:
1.指针和引用的定义和性质区别: (1)指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已。如: int a=1;int *p=&a; int a=1;int &b=a; 上面定义了一个整形变量和一个指针变量p,该指针变量指向a的存储单元,即p的值是a存储单元的地址。 而下面2句定义了一个整形变量a和这个整形a的引用b,事实上a和b是同一个东西,在内存占有同一个存储单元。 (2)可以有const指针,但是没有const引用; (3)指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的) (4)指针的值可以为空,但是引用的值不能为NULL,并且引用在定义的时候必须初始化; (5)指针的值在初始化后可以改变,即指向其它的存储单元,而引用在进行初始化后就不会再改变了。 (6)"sizeof引用"得到的是所指向的变量(对象)的大小,而"sizeof指针"得到的是指针本身的大小; (7)指针和引用的自增(++)运算意义不一样;
首先我测试了第一条,但是发现并不是这样子,求高手指教。代码如下:
class A{ char name[]; int age; }; void init() { A a; A &aref1 = a; A *aPointer = &a; }
对应的汇编代码如下:
_Z4initv: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 subl $16, %esp leal -12(%ebp), %eax movl %eax, -8(%ebp) leal -12(%ebp), %eax movl %eax, -4(%ebp) leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret
看上面的汇编代码我们会发现指针和引用的操作都是一样的,且引用也占据着栈上的内存[-8(%ebp)]。
下面来看看引用和指针作为函数参数的表现是怎样的?
先来看看引用的情况,代码如下:
class A{ public: char name[32]; int age; }; void init(int off, A& a) { a.age = 25 + off; }
对应的汇编代码如下:
_Z4initiR1A: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 movl 8(%ebp), %eax leal 25(%eax), %edx movl 12(%ebp), %eax movl %edx, 32(%eax) popl %ebp .cfi_def_cfa 4, 4 .cfi_restore 5 ret .cfi_endproc
从语句
movl 12(%ebp), %eax
movl %edx, 32(%eax)
我们看出【12(%ebp)】这里存放着传入A的实例的地址。
再来看看指针的情况,代码如下:
class A{ public: char name[32]; int age; }; void init(int off, A* a) { a->age = 25 + off; }
对应的汇编如下:
_Z4initiP1A: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 movl 8(%ebp), %eax leal 25(%eax), %edx movl 12(%ebp), %eax movl %edx, 32(%eax) popl %ebp .cfi_def_cfa 4, 4 .cfi_restore 5 ret .cfi_endproc
我们可以看出和上面引用的情况是一样的。
3. 对引用取地址
代码如下:
class A{ char name[]; int age; }; void init() { A a; A &aref1 = a; A *aPointer = &a; int ptr = (int)&aref1; }
汇编如下:
_Z4initv: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 subl $16, %esp leal -16(%ebp), %eax movl %eax, -12(%ebp) leal -16(%ebp), %eax movl %eax, -8(%ebp) movl -12(%ebp), ea%x movl %eax, -4(%ebp) leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc
我们可以看到只有在对引用类型取地址之后才将a的地址赋值给它。说明c++对引用类型的取地址操作进行了封装。