引用:有了限制的指针

如果我们要将引用类型聊明白,我们需要从指针类型开始。指针类型的变量存储的值,其实是一个内存地址,这块内存地址可能在栈上,也可能在堆上。而且指针还支持加减运算,可谓非常灵活。比如下面这个简单的例子

#include <stdio.h>
void swap(int *a,int *b) {
    int tmp = *a;
    *a = *b;
    *b = tmp;
}
int main() {
    int a = 9;
    int b = 1;
    swap(&a,&b);
    printf("a: %d b: %d",a,b);
}
swap:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-24], rdi ; 将a的内存地址放入[rbp-24]这块内存中
        mov     QWORD PTR [rbp-32], rsi ; 将b的内存地址放入[rbp-32]这块内存中
        mov     rax, QWORD PTR [rbp-24] ; 将a的内存地址放入rax寄存器中
        mov     eax, DWORD PTR [rax]    ; 读取a的内存地址对应的内存数据到eax寄存器中
        mov     DWORD PTR [rbp-4], eax  ; 将eax的值即a对应的数据(9) 放入到[rbp-4]这块内存中
        mov     rax, QWORD PTR [rbp-32]
        mov     edx, DWORD PTR [rax]
        mov     rax, QWORD PTR [rbp-24]
        mov     DWORD PTR [rax], edx
        mov     rax, QWORD PTR [rbp-32]
        mov     edx, DWORD PTR [rbp-4]
        mov     DWORD PTR [rax], edx
        nop
        pop     rbp
        ret
.LC0:
        .string "a: %d b: %d"
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     DWORD PTR [rbp-4], 9
        mov     DWORD PTR [rbp-8], 1
        lea     rdx, [rbp-8] ; 获取变量b的内存地址 &b
        lea     rax, [rbp-4] ; 获取变量a的内存地址 &a
        mov     rsi, rdx
        mov     rdi, rax
        call    swap
        mov     edx, DWORD PTR [rbp-8]
        mov     eax, DWORD PTR [rbp-4]
        mov     esi, eax
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        mov     eax, 0
        leave
        ret

通过汇编代码我们可以发现,所谓的指针类型无非对应两条指令,一条为 lea 获取对应的内存地址,一条为 [memory_address] 获取内存地址对应的值。具体可以看我在代码中对应的注释。在这里,变量a与变量b都在main函数的栈帧中,属于栈内存。

通过上面的例子,我们可以发现我们获取一个变量的内存地址非常的容易,利用内存地址获取对应的数据也非常容易。但是引用类型就没有这么灵活,第一,我们不能随意的获取某个变量的内存地址,第二,也不存在通过某种运算符可以从内存地址提取出对应的值。而且引用类型存储的内存地址,都是堆内存。比如下面这段代码

Object obj = new Object();

这段代码的含义是,在堆内存中创建Object类型的对象,并将内存首地址赋值给obj这个变量。当我们使用 obj.wait() 时,代表着,通过obj找到真实的对象,然后再通过对象去寻找对应的wait方法

引用类型失去了随意获取内存地址的能力,这让他丧失了一定的灵活性,但是却更加的安全。

这里我们发现,无论是什么类型在CPU层面都消失了,那么类型究竟在哪里发挥了作用呢?主要有两个方面,第一,在我们编写代码的时候,类型能够让我们规避很多由于粗心导致的问题。第二,编译器在将高级编程语言转换为机器码的时候,提供了一些信息,比如操作内存的大小,是一个字节还是4个字节。以及对一些数据的类型做校验,如果不满足数据不满足这个类型的格式,那么就会报错,编译失败。

以上,就是我对指针以及引用的一些思考,希望对你有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值