C中只有传值(PV)和传地址(PP)。有些语言仅仅有传地址,没有传值。好象FORTRAN就是。
实际上从汇编开始理解,传递(包括参数和返回)要么是PV要么是PP。那么引用是什么东西?
引用是C++不得以产生的概念。如果没有C的PV,如FORTRAN那样全是引用(一种PP),也就不会出现引用的概念。
下面的小程序和对应的汇编可以说明引用本质是什么。
从func0和func1的调用可以看出引用本质就是地址传递(PP)。2个函数调用的汇编一样的。
func2返回引用,实际是返回地址,也是地址传递(PP)
那么引用有好处吗?我个人意见,不多。除非万不得已非用不可,建议千万不要使用。
使用了,后果是让简单的程序无法读懂(不是因为引用概念复杂),尤其是分模块的情况下。
比如:
int i = 1;
return i;
的本意很清楚,可以有引用的情况下,这2行的意义是不确定的。比如往前看才能确定。
function(i); 也是一样,本来清楚的东西变为不确定。
实际上引用就是PP,但是一种用编译器做了伪装的PP。因此使程序更不容易读。
欢迎批评和讨论。
CODE:
#include <stdio.h>
int func0(int &i)
{
i++;
return 100;
}
int func1(int *ip)
{
(*ip) ++;
return 101;
}
int& func2(int i)
{
static int ii = 123;
return ii;
}
main()
{
int i, j;
i = 4;
j = 104;
j = func0(i);
//printf("i = %d j = %d\n", i, j);
j = func1(&i);
//printf("i = %d j = %d\n", i, j);
j = func2(9);
//printf("i = %d j = %d\n", i, j);
}
.file "t2.c"
.text
.align 2
.globl _Z5func0Ri
.type _Z5func0Ri,@function
_Z5func0Ri:
.LFB2:
pushl %ebp
.LCFI0:
movl %esp, %ebp
.LCFI1:
movl 8(%ebp), %eax
incl (%eax)
movl $100, %eax
leave
ret
.LFE2:
.Lfe1:
.size _Z5func0Ri,.Lfe1-_Z5func0Ri
.align 2
.globl _Z5func1Pi
.type _Z5func1Pi,@function
_Z5func1Pi:
.LFB4:
pushl %ebp
.LCFI2:
movl %esp, %ebp
.LCFI3:
movl 8(%ebp), %eax
incl (%eax)
movl $101, %eax
leave
ret
.LFE4:
.Lfe2:
.size _Z5func1Pi,.Lfe2-_Z5func1Pi
.align 2
.globl _Z5func2i
.type _Z5func2i,@function
_Z5func2i:
.LFB6:
pushl %ebp
.LCFI4:
movl %esp, %ebp
.LCFI5:
subl $4, %esp
.LCFI6:
movl $123, -4(%ebp)
leal -4(%ebp), %eax
leave
ret
.LFE6:
.Lfe3:
.size _Z5func2i,.Lfe3-_Z5func2i
.align 2
.globl main
.type main,@function
main:
.LFB8:
pushl %ebp
.LCFI7:
movl %esp, %ebp
.LCFI8:
subl $8, %esp
.LCFI9:
andl $-16, %esp
movl $0, %eax
subl %eax, %esp
movl $4, -4(%ebp)
movl $104, -8(%ebp)
subl $12, %esp
leal -4(%ebp), %eax
pushl %eax
.LCFI10:
call _Z5func0Ri
addl $16, %esp
movl %eax, -8(%ebp)
subl $12, %esp
leal -4(%ebp), %eax
pushl %eax
call _Z5func1Pi
addl $16, %esp
movl %eax, -8(%ebp)
subl $12, %esp
pushl $9
call _Z5func2i
addl $16, %esp
movl (%eax), %eax
movl %eax, -8(%ebp)
movl $0, %eax
leave
ret
.LFE8:
.Lfe4:
.size main,.Lfe4-main
.ident "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"
int func0(int &i)
{
i++;
return 100;
}
int func1(int *ip)
{
(*ip) ++;
return 101;
}
int& func2(int i)
{
static int ii = 123;
return ii;
}
main()
{
int i, j;
i = 4;
j = 104;
j = func0(i);
//printf("i = %d j = %d\n", i, j);
j = func1(&i);
//printf("i = %d j = %d\n", i, j);
j = func2(9);
//printf("i = %d j = %d\n", i, j);
}
.file "t2.c"
.text
.align 2
.globl _Z5func0Ri
.type _Z5func0Ri,@function
_Z5func0Ri:
.LFB2:
pushl %ebp
.LCFI0:
movl %esp, %ebp
.LCFI1:
movl 8(%ebp), %eax
incl (%eax)
movl $100, %eax
leave
ret
.LFE2:
.Lfe1:
.size _Z5func0Ri,.Lfe1-_Z5func0Ri
.align 2
.globl _Z5func1Pi
.type _Z5func1Pi,@function
_Z5func1Pi:
.LFB4:
pushl %ebp
.LCFI2:
movl %esp, %ebp
.LCFI3:
movl 8(%ebp), %eax
incl (%eax)
movl $101, %eax
leave
ret
.LFE4:
.Lfe2:
.size _Z5func1Pi,.Lfe2-_Z5func1Pi
.align 2
.globl _Z5func2i
.type _Z5func2i,@function
_Z5func2i:
.LFB6:
pushl %ebp
.LCFI4:
movl %esp, %ebp
.LCFI5:
subl $4, %esp
.LCFI6:
movl $123, -4(%ebp)
leal -4(%ebp), %eax
leave
ret
.LFE6:
.Lfe3:
.size _Z5func2i,.Lfe3-_Z5func2i
.align 2
.globl main
.type main,@function
main:
.LFB8:
pushl %ebp
.LCFI7:
movl %esp, %ebp
.LCFI8:
subl $8, %esp
.LCFI9:
andl $-16, %esp
movl $0, %eax
subl %eax, %esp
movl $4, -4(%ebp)
movl $104, -8(%ebp)
subl $12, %esp
leal -4(%ebp), %eax
pushl %eax
.LCFI10:
call _Z5func0Ri
addl $16, %esp
movl %eax, -8(%ebp)
subl $12, %esp
leal -4(%ebp), %eax
pushl %eax
call _Z5func1Pi
addl $16, %esp
movl %eax, -8(%ebp)
subl $12, %esp
pushl $9
call _Z5func2i
addl $16, %esp
movl (%eax), %eax
movl %eax, -8(%ebp)
movl $0, %eax
leave
ret
.LFE8:
.Lfe4:
.size main,.Lfe4-main
.ident "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"
![nixsky[www.nixsky.com]](/templets/images/toplogo.gif)

