• 从汇编看c++中的引用和指针


    在c++中,引用和指针具有相同的作用,都可以用来在函数里面给变函数外面对象或者变量的值,下面就来看他们的原理。

    首先是引用情形下的c++源码:

    void add(int a, int b, int&c) {
        c = a + b;
    }
    
    
    int main() {
        int a = 1;
        int b = 2;
        int c = 0;
        add(a, b, c);
        
    }

    下面是main对应的汇编码:

    ; 6    : int main() {
    
        push    ebp
        mov    ebp, esp
        sub    esp, 12                    ; 为该调用函数的栈空间预留12byte,用来存储局部变量a,b, c
    
    ; 7    :     int a = 1;
    
        mov    DWORD PTR _a$[ebp], 1;初始化a _a$为a存储空间地址相对于ebp基址的偏移量
    
    ; 8    :     int b = 2;
    
        mov    DWORD PTR _b$[ebp], 2;初始化b _b$为b存储空间地址相对于ebp基址的偏移量
    
    ; 9    :     int c = 0;
    
        mov    DWORD PTR _c$[ebp], 0;初试化c _c$为c存储空间地址相对于ebp基址的偏移量
    
    ; 10   :     add(a, b, c);
        lea    eax, DWORD PTR _c$[ebp]; 获取c存储空间相对于ebp基址的偏移量(即c存储单元的偏移地址),放在寄存器eax中
        push    eax;保存c存储空间的偏移量到堆栈中
        mov    ecx, DWORD PTR _b$[ebp];将b存储空间里面的值(即b的值)放在寄存器ecx中
        push    ecx;保存b存储空间的值到堆栈中
        mov    edx, DWORD PTR _a$[ebp];将a存储空间里面的值(即a的值)放在寄存器edx里面
        push    edx;保存a存储空间的到堆栈
        
        ;上面push eax push ecx push edx在栈里面存储了原来局部变量a,b,c的值,只不过对于c来说,存储的是c存储空间的偏移地址
        ;因此,对于a,b来说,也就是将他们的值得一份拷贝存了起来,也就是传值;而c只是存储了自己存储空间的偏移地址,也就是传地址
        call    ?add@@YAXHHAAH@Z            ; 调用add函数,上面的语句已经为传递参数做好了准备
        add    esp, 12                    ; 由于刚才为调用函数add传递参数进行了压栈,这里释放栈空间,即释放参数
                                    ;这就是为什么函数调用完成后局部变量和参数无效的原因,因为他们的空间被释放了
    
    ; 11   :     
    ; 12   : }
    
        xor    eax, eax
        mov    esp, ebp
        pop    ebp
        ret    0

    下面是函数add对应的汇编码:

    ; 1    : void add(int a, int b, int&c) {
    
        push    ebp
        mov    ebp, esp
    
    ; 2    :     c = a + b;
    
        mov    eax, DWORD PTR _a$[ebp];取参数a的值到寄存器eax中
        add    eax, DWORD PTR _b$[ebp];取参数b的值与eax中a的值相加,结果放到eax中
        mov    ecx, DWORD PTR _c$[ebp];去c的偏移地址放到寄存器ecx中
        mov    DWORD PTR [ecx], eax;将eax中的结果写到由ecx指定的地址单元中去,即c所在存储单元
    
    ; 3    : }
    
        pop    ebp
        ret    0


    从上面可以看到,对于传值,c++确实传的是一份值拷贝,而对于引用,虽然是传值的形式,但是其实编译器内部传递的是值得地址

    下面是指针的情形的c++源码:

    void add(int a, int b, int* c) {
        *c = a + b;
    }
    
    
    int main() {
        int a = 1;
        int b = 2;
        int c = 0;
        add(a, b, &c);
        
    }

    mian函数对应的汇编码:

    ; 6    : int main() {
    
        push    ebp
        mov    ebp, esp
        sub    esp, 12                    ; 
    
    ; 7    :     int a = 1;
    
        mov    DWORD PTR _a$[ebp], 1
    
    ; 8    :     int b = 2;
    
        mov    DWORD PTR _b$[ebp], 2
    
    ; 9    :     int c = 0;
    
        mov    DWORD PTR _c$[ebp], 0
    
    ; 10   :     add(a, b, &c);
    
        lea    eax, DWORD PTR _c$[ebp]
        push    eax
        mov    ecx, DWORD PTR _b$[ebp]
        push    ecx
        mov    edx, DWORD PTR _a$[ebp]
        push    edx
        call    ?add@@YAXHHPAH@Z            ; add
        add    esp, 12                    ; 
    ; 11   :     
    ; 12   : }
    
        xor    eax, eax
        mov    esp, ebp
        pop    ebp
        ret    0


    add函数对应的汇编码:

    ; 1    : void add(int a, int b, int* c) {
    
        push    ebp
        mov    ebp, esp
    
    ; 2    :     *c = a + b;
    
        mov    eax, DWORD PTR _a$[ebp]
        add    eax, DWORD PTR _b$[ebp]
        mov    ecx, DWORD PTR _c$[ebp]
        mov    DWORD PTR [ecx], eax
    
    ; 3    : }
    
        pop    ebp
        ret    0

    可以看到,指针和引用的汇编码一样,因此两者的作用也一样

  • 相关阅读:
    Linux Shell编程入门
    vim 文件在linux不换行,只显示^M解决办法
    服务器高性能程序 磁盘I/O篇
    车牌识别_转自别人的博客
    ubuntu网络简单设置
    C++设计模式(转载)
    结构算法之道
    C++设计模式工厂方法
    二叉树的深度优先遍历、广度优先遍历和非递归遍历
    iptables
  • 原文地址:https://www.cnblogs.com/chaoguo1234/p/3061342.html
Copyright © 2020-2023  润新知