从内存与汇编的角度理解C语言指针第03篇:执行 *p = 2 和 **pp = 3 时CPU干了些什么?【视频解析】

!!!想看视频解析请点击这里!!!

一、C程序

int main(void) {
    int a = 1;      // 定义变量 a,值为 1
    int *p = &a;    // 定义指针 p,指向 a
    *p = 2;         // 修改指针 p 所指变量 a 的值为 2,即 a = 2
    int **pp = &p;  // 定义指针 pp,指向 p
    **pp = 3;       // 修改指针 pp 所指变量 p 的所指变量 a 的值为 3,即 a = 3
    return 0;
}

二、对应的汇编代码

; C代码:int a = 1;
mov    DWORD PTR [rbp-0xc],0x1     // 把数字 1 存放到内存单元[rbx-0xc]处(即变量 a 的内存单元)
								   
; C代码:int *p = &a;          
lea    rax,[rbp-0xc]               // 把内存单元[rbx-0xc]的地址存入rax寄存器
mov    QWORD PTR [rbp-0x18],rax    // 把rax寄存器中的值存放到内存单元[rbp-0x18]处
								   // 此时内存单元[rbp-0x18]里的值就是内存单元[rbx-0xc]的地址

; C代码:*p = 2;                
mov    rax,QWORD PTR [rbp-0x18]    // 把内存单元[rbp-0x18]的值(即变量 a 的地址)存入rax寄存器
mov    DWORD PTR [rax],0x2         // 把数字 2 存放到内存单元[rax]处(即变量 a 的内存单元)
								   // 此时 a 的值变成了 2
								   
; C代码:int **pp = &p;         
lea    rax,[rbp-0x18]              // 把内存单元[rbp-0x18]的地址存入rax寄存器
mov    QWORD PTR [rbp-0x8],rax     // 把rax寄存器中的值存放到内存单元[rbp-0x8]处
								   // 此时内存单元[rbp-0x8]里的值就是内存单元[rbx-0x18]的地址
								   // 而内存单元[rbp-0x18]里的值又是内存单元[rbx-0xc]的地址
								   // 而内存单元[rbx-0xc]的值即是变量 a 的值,是 2

; C代码:**pp = 3;             
mov    rax,QWORD PTR [rbp-0x8]     // 把内存单元[rbp-0x8]的值(即变量 p 的地址)存入rax寄存器
mov    rax,QWORD PTR [rax]         // 把内存单元[rax]的值(即变量 a 的地址)存入rax寄存器
mov    DWORD PTR [rax],0x3         // 把数字 3 存放到内存单元[rax]处(即变量 a 的内存单元)
								   // 此时 a 的值变成了 3

三、内存布局

1、执行完int a = 1之后的内存布局

变量变量地址内存地址内存值
a&a0x61fe140x01

2、执行完int *p = &a之后的内存布局

变量变量地址内存地址内存值
p&p0x61fe080x61fe14
a&a0x61fe140x01

这里,变量p的内存值是变量a的内存地址。

3、执行完*p = 2之后的内存布局

变量变量地址内存地址内存值
p&p0x61fe080x61fe14
a&a0x61fe140x02

与上一步的区别是,变量a的内存值从1变成了2

4、执行完int **pp = &p之后的内存布局

变量变量地址内存地址内存值
pp&pp0x61fe180x61fe08
p&p0x61fe080x61fe14
a&a0x61fe140x02

这里,变量pp的内存值是变量p的内存地址,变量p的内存值是变量a的内存地址。

5、执行完**pp = 3之后的内存布局

变量变量地址内存地址内存值
pp&pp0x61fe180x61fe08
p&p0x61fe080x61fe14
a&a0x61fe140x03

与上一步的区别是,变量a的内存值从2变成了3

四、执行*p = 2时CPU干了些什么

准确来说,干的就是上面的汇编代码里面做的事情:

mov    rax,QWORD PTR [rbp-0x18]    // 把内存单元[rbp-0x18]的值(即变量 a 的地址)存入rax寄存器
mov    DWORD PTR [rax],0x2         // 把数字 2 存放到内存单元[rax]处(即变量 a 的内存单元)
								   // 此时 a 的值变成了 2

与内存布局对应着来理解就是:

  1. CPU已经知道变量p的内存地址是0x61fe08,于是去把它的内存值取出来,这个值是0x61fe14,把这个值放到了rax寄存器中。
  2. CPU发现rax寄存器中的值也是一个内存地址,接下来就把数字2存放到了这个地址所在的内存单元处。

那CPU是怎么知道内存单元或寄存器中的值是内存地址的呢?这是我们汇编指令告诉它的。
[rbp-0x18][rax]中的那个[]的作用就是:访问括号里面的内存地址。
也就是说,指令里面有[],CPU就知道是内存地址了。

五、执行**pp = 3时CPU干了些什么

汇编代码:

mov    rax,QWORD PTR [rbp-0x8]     // 把内存单元[rbp-0x8]的值(即变量 p 的地址)存入rax寄存器
mov    rax,QWORD PTR [rax]         // 把内存单元[rax]的值(即变量 a 的地址)存入rax寄存器
mov    DWORD PTR [rax],0x3         // 把数字 3 存放到内存单元[rax]处(即变量 a 的内存单元)
								   // 此时 a 的值变成了 3

与内存布局对应着来理解就是:

  1. CPU已经知道变量pp的内存地址是0x61fe18,于是去把它的内存值取出来,这个值是0x61fe08,把这个值放到了rax寄存器中。
  2. CPU发现这时rax寄存器中的值也是一个内存地址0x61fe08,于是去把这个地址对应的内存值取出来,这个值是0x61fe14,这个值仍然存放到rax寄存器中。
  3. CPU发现rax寄存器中的值还是一个内存地址,接下来就把数字3存放到了这个地址所在的内存单元处。

六、总结

在CPU眼中是没有变量一说的,它不知道appp,它只知道指令,比如:

指令让它从内存里取值放到寄存器;
指令让它把寄存器中的值当成一个地址,然后去另一块内存区域里取值,还是放到寄存器里面;
指令让它把数字3存放到内存区域里面。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值