指针和引用有何区别?

内容会比较粗略,且需些许汇编的知识。

指针和引用的区别在哪?

学过C++的同学都能答上几点:

  • 引用是别名
  • 引用必须初始化,并且初始化后不能重新引用其他变量
  • 指针是所指内容的地址

 但引用是别名,这是C++语法规定的。

那引用到底在汇编层面和指针有什么区别呢?

无区别

这是我当时自己观察各种相关资料得出的结论,引用会被C++ 编译器当做const指针来进行操作。

来看个例子:

汇编打开引用的面具

先分别用指针、引用来写个函数swap 

//指针版
void swap(int *a, int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}


//引用版
void swap(int &a, int &b)
{
    int temp = a;
    a = b;
    b = temp;
}

 可以利用 gcc  -S 输出汇编:

引用版汇编

__Z4swapRiS_:                           ## @_Z4swapRiS_
        .cfi_startproc
## %bb.0:
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset %rbp, -16
        movq    %rsp, %rbp          
        .cfi_def_cfa_register %rbp
        movq    %rdi, -8(%rbp)     # 传入的第一个参数存放到%rbp-8  (应该是采用的寄存器传参,而不是常见的压栈)
        movq    %rsi, -16(%rbp)    # 第二个参数 存放到 %rbp-16
        movq    -8(%rbp), %rsi     # 第一个参数赋给 rsi
        movl    (%rsi), %eax       # 以第一个参数为地址取出值赋给eax,取出*a暂存寄存器
        movl    %eax, -20(%rbp)    # temp = a
        movq    -16(%rbp), %rsi    # 将第二个参数重复上面的
        movl    (%rsi), %eax
        movq    -8(%rbp), %rsi    
        movl    %eax, (%rsi)       # a = b
        movl    -20(%rbp), %eax    # eax = temp
        movq    -16(%rbp), %rsi
        movl    %eax, (%rsi)       # b = temp
        popq    %rbp
        retq
        .cfi_endproc
                                        ## -- End function

再来一个函数调用引用版本swap

void call() 
{
    int a = 10;
    int b = 3;
    int &ra = a;
    int &rb = b;
    swap(ra, rb);
}

对应的汇编:

__Z4callv:                              ## @_Z4callv
        .cfi_startproc
## %bb.0:
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset %rbp, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register %rbp
        subq    $32, %rsp
        leaq    -8(%rbp), %rax          # rax中是b的地址
        leaq    -4(%rbp), %rcx          # rcx中是a的地址
        movl    $10, -4(%rbp)   
        movl    $3, -8(%rbp)            # 分别初始化a、b
        movq    %rcx, -16(%rbp)         # 赋给ra引用
        movq    %rax, -24(%rbp)         # 赋给rc引用
        movq    -16(%rbp), %rdi         # 寄存器传参, -16(%rbp)就是rcx中的值也就是a的地址
        movq    -24(%rbp), %rsi         # 略
        callq   __Z4swapRiS_
        addq    $32, %rsp
        popq    %rbp
        retq

从上面可以看到给引用赋初值,就是把所引用对象的地址赋给引用所在内存,和指针是一样的。

再看指针的汇编

指针版汇编

__Z4swapPiS_:                           ## @_Z4swapPiS_
        .cfi_startproc
## %bb.0:
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset %rbp, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register %rbp
        movq    %rdi, -8(%rbp)
        movq    %rsi, -16(%rbp)
        movq    -8(%rbp), %rsi
        movl    (%rsi), %eax
        movl    %eax, -20(%rbp)
        movq    -16(%rbp), %rsi
        movl    (%rsi), %eax
        movq    -8(%rbp), %rsi
        movl    %eax, (%rsi)
        movl    -20(%rbp), %eax
        movq    -16(%rbp), %rsi
        movl    %eax, (%rsi)
        popq    %rbp
        retq
        .cfi_endproc
                                        ## -- End function

 真是完全一样,并不是直接复制的引用汇编,而是真的在编译器实现上都是相同的方式。

指针版调用

void pointer_call()
{
    int a = 10;
    int b = 3;
    int *pa = &a;
    int *pb = &b;
    swap(pa, pb);
}

 改了函数名,对应汇编:

__Z12pointer_callv:                     ## @_Z12pointer_callv
        .cfi_startproc
## %bb.0:
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset %rbp, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register %rbp
        subq    $32, %rsp
        leaq    -8(%rbp), %rax
        leaq    -4(%rbp), %rcx
        movl    $10, -4(%rbp)
        movl    $3, -8(%rbp)
        movq    %rcx, -16(%rbp)
        movq    %rax, -24(%rbp)
        movq    -16(%rbp), %rdi
        movq    -24(%rbp), %rsi
        callq   __Z4swapPiS_
        addq    $32, %rsp
        popq    %rbp
        retq

也几乎完全是一样。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值