C++函数中引用参数与指针参数分析

来源:互联网 发布:linux终端快捷键设置 编辑:程序博客网 时间:2024/05/20 19:15

0.

采用的源代码如下,通过宏来控制

#define PTR_TEST#ifdef PTR_TESTvoid test_arg_ptr(int *ptr){  *ptr = 4;}#elsevoid test_arg_ref(int& ref){  ref = 4;}#endifintmain(int argc, char *argv[]) {  int i = 0;#ifdef PTR_TEST  test_arg_ptr(&i);#else  test_arg_ref(i);#endif                                                                                                          return 0;}



1 参数为指针形式,其汇编如下:

main():  4005c8:   55                      push   %rbp  4005c9:   48 89 e5                mov    %rsp,%rbp  4005cc:   48 83 ec 20             sub    $0x20,%rsp  4005d0:   89 7d ec                mov    %edi,-0x14(%rbp)  4005d3:   48 89 75 e0             mov    %rsi,-0x20(%rbp)  4005d7:   c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)  4005de:   48 8d 45 fc             lea    -0x4(%rbp),%rax -- 即取变量i的地址  4005e2:   48 89 c7                mov    %rax,%rdi  --- 当参数少于7个时,参数从左到右: rdi, rsi, rdx, rcx, r8, r9  4005e5:   e8 ca ff ff ff          callq  4005b4 <_Z12test_arg_ptrPi>  4005ea:   b8 00 00 00 00          mov    $0x0,%eax                                                   4005ef:   c9                      leaveq   4005f0:   c3                      retq_Z12test_arg_ptrPi():  4005b4:   55                      push   %rbp  4005b5:   48 89 e5                mov    %rsp,%rbp  4005b8:   48 89 7d f8             mov    %rdi,-0x8(%rbp) ----0x8(%rbp)即为形参  4005bc:   48 8b 45 f8             mov    -0x8(%rbp),%rax   4005c0:   c7 00 04 00 00 00       movl   $0x4,(%rax)  4005c6:   c9                      leaveq  4005c7:   c3                      retq
    值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。

    指针传递参数本质上是值传递的方式,它所传递的是一个地址值。程序通过间址方式修改指针所指对象的值。


2 参数为引用形式:
4005c8:   55                      push   %rbp  4005c9:   48 89 e5                mov    %rsp,%rbp  4005cc:   48 83 ec 20             sub    $0x20,%rsp  4005d0:   89 7d ec                mov    %edi,-0x14(%rbp)  4005d3:   48 89 75 e0             mov    %rsi,-0x20(%rbp)  4005d7:   c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)  4005de:   48 8d 45 fc             lea    -0x4(%rbp),%rax  4005e2:   48 89 c7                mov    %rax,%rdi  4005e5:   e8 ca ff ff ff          callq  4005b4 <_Z12test_arg_refRi>  4005ea:   b8 00 00 00 00          mov    $0x0,%eax  4005ef:   c9                      leaveq   4005f0:   c3                      retq_Z12test_arg_refRi():  4005b4:   55                      push   %rbp  4005b5:   48 89 e5                mov    %rsp,%rbp  4005b8:   48 89 7d f8             mov    %rdi,-0x8(%rbp)  4005bc:   48 8b 45 f8             mov    -0x8(%rbp),%rax  4005c0:   c7 00 04 00 00 00       movl   $0x4,(%rax)  4005c6:   c9                      leaveq  4005c7:   c3                      retq

可以看出与指针传递的结果完全一样,或者说编译器帮助我们作了从引用到指针的转换。

从语言层面来说:
1)引用在创建的同时必须初始化,即引用到一个有效的对象;而指针在定义的时候不必初始化,可以在定义后面的任何地方重新赋值.
(2)不存在NULL引用,引用必须与合法的存储单元关联;而指针则可以是NULL.
(3)引用一旦被初始化为指向一个对象,它就不能被改变不另一个对象的引用;(地址不可变) 而指针在任何时候都可以改变为指向另一个对象.给引用赋值并不是改变它和原始对象的绑定关系.
(4)引用的创建和销毁并不会调用类的拷贝构造函数

从实现来看,引用是用指针来实现的。

原创粉丝点击