美文网首页
对象直接访问与指针访问

对象直接访问与指针访问

作者: wangwhatlh | 来源:发表于2021-11-06 11:59 被阅读0次

    代码

    class Person{
        public:
            int id;
            int age;
            int height;
            void display(){
                cout<<this<<"   id = "<<id<<",age = "<<age<<",height = "<<height<<endl;
            }
    };
    int main(int argc, const char * argv[]) {
        Person person;
        person.id = 10;
        person.age = 20;
        person.height = 30;
        person.display();
        
        // 指针访问 1
        Person *p1 = (Person *)&person;
        p1->age = 40;
        p1->height = 50;
        p1->display();
        // 指针访问 2
        Person *p2 = (Person *)&person.id;
        p2->age = 40;
        p2->height = 50;
        p2->display();
        // 指针访问 3
        Person *p3 = (Person *)&person.age;
        p3->age = 40;
        p3->height = 50;
        p3->display();
        return 0;
    }
    

    打印如下
    0x7ffeefbff430 id = 10,age = 20,height = 30
    0x7ffeefbff430 id = 10,age = 40,height = 50
    0x7ffeefbff430 id = 10,age = 40,height = 50
    0x7ffeefbff434 id = 40,age = 40,height = 50
    可以看出第四个打印不一样,细思一下,大致可以猜到是因为person对象与其第一个成员id地址都是一样,正如打印0x7ffeefbff430,而第四个是0x7ffeefbff434是指向第二个成员age,正好后4个字节。但还是有疑问滴,明明没改id,为啥变呢,那就探究下其汇编代码了,在这之前先简单了解下指令相关:
    /**
    *%rax 通常用于存储函数调用的返回结果,同时也用于乘法和除法指令中。
    %rsp 是堆栈指针寄存器,通常会指向栈顶位置
    %rbp 是栈帧指针寄存器,用于标识当前栈帧的起始位置
    %rdi,%rsi,%rdx,%rcx,%r8,%r9 用来传递函数参数,依次对应第1参数,第2参数至第6参数
    %rbx,%r12,%r13,%14,%15 ,%r10,%r11 用作数据存储,属于通用性更为广泛的寄存器,编译器或汇编程序可以根据需要存储任何数据。
    */
    对象访问:

        0x1000030b6 <+22>:  movl   $0xa, -0x20(%rbp) // 将10赋给该地址所在内存值,可以判断该地址是id成员的地址
        0x1000030bd <+29>:  movl   $0x14, -0x1c(%rbp) // person.age = 20;
        0x1000030c4 <+36>:  movl   $0x1e, -0x18(%rbp) // person.height = 30;
        0x1000030cb <+43>:  leaq   -0x20(%rbp), %rdi // 
        0x1000030cf <+47>:  callq  0x100003160     //     person.display();
    
    

    很明显,只是直接赋值方式
    P1:

    /**
        Person *p1 = (Person *)&person;
        p1->age = 40;
        p1->height = 50;
        p1->display();
    */
        0x1000030d4 <+52>:  leaq   -0x20(%rbp), %rax // 将-0x20(%rbp)的地址拷贝到rax中,这里应该是person 的地址,p1指针的数据
        0x1000030d8 <+56>:  movq   %rax, -0x28(%rbp) // 
        0x1000030dc <+60>:  movq   -0x28(%rbp), %rax  // -0x28(%rbp)赋给rax
        0x1000030e0 <+64>:  movl   $0x28, 0x4(%rax)  // rax下4字节的数据存储40,age
        0x1000030e7 <+71>:  movq   -0x28(%rbp), %rax 
        0x1000030eb <+75>:  movl   $0x32, 0x8(%rax) // 将50赋给0x8(%rax) ,第8字节后数据height
        0x1000030f2 <+82>:  movq   -0x28(%rbp), %rdi    
        0x1000030f6 <+86>:  callq  0x100003160
    

    可以看出底层是通过指针地址偏移指向来修改成员变量的
    P2:

        0x1000030fb <+91>:  leaq   -0x20(%rbp), %rax
        0x1000030ff <+95>:  movq   %rax, -0x30(%rbp) // 
        0x100003103 <+99>:  movq   -0x30(%rbp), %rax
        0x100003107 <+103>: movl   $0x28, 0x4(%rax)
        0x10000310e <+110>: movq   -0x30(%rbp), %rax
        0x100003112 <+114>: movl   $0x32, 0x8(%rax)
        0x100003119 <+121>: movq   -0x30(%rbp), %rdi
        0x10000311d <+125>: callq  0x100003160   
    

    P3:

        0x100003122 <+130>: leaq   -0x20(%rbp), %rax
        0x100003126 <+134>: addq   $0x4, %rax // 递增%rdx 4字节
        0x10000312c <+140>: movq   %rax, -0x38(%rbp)
        0x100003130 <+144>: movq   -0x38(%rbp), %rax
        0x100003134 <+148>: movl   $0x28, 0x4(%rax)
        0x10000313b <+155>: movq   -0x38(%rbp), %rax
        0x10000313f <+159>: movl   $0x32, 0x8(%rax)
        0x100003146 <+166>: movq   -0x38(%rbp), %rdi
        0x10000314a <+170>: callq  0x100003160 
    

    p3指向了原person.age,也就意味着其首成员p3->id是原person.age的值,这就是解释了为啥p3->id为40。
    同样值得注意的是person.display())与p3->display()结果又不一样,因为两者地址已经不一样

    相关文章

      网友评论

          本文标题:对象直接访问与指针访问

          本文链接:https://www.haomeiwen.com/subject/opqjzltx.html