从汇编看c++中引用与指针的使用分析

2016-02-19 09:56 19 1 收藏

get新技能是需要付出行动的,即使看得再多也还是要动手试一试。今天图老师小编跟大家分享的是从汇编看c++中引用与指针的使用分析,一起来学习了解下吧!

【 tulaoshi.com - 编程语言 】

首先是引用情形下的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;

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

    mov    DWORD PTR _b$[ebp], 2;初始化b _b$为b存储空间地址相对于ebp基址的偏移量

; 9    :     int c = 0;

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

    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;

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

    mov    DWORD PTR _b$[ebp], 2

; 9    :     int c = 0;

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

    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

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

来源:http://www.tulaoshi.com/n/20160219/1592736.html

延伸阅读
在学习c/c+过程中,指针是一个比较让人头痛的问题,稍微不注重将会是程序编译无法通过,甚至造成死机。在程序设计过程中,指针也往往是产生隐含bug的原因。下面就来谈谈指针的应用以及需要注重的一些问题,里面也许就有你平时没有注重到的问题,希望能帮助各位读者理解好指针。 !-- frame contents -- !-- /frame contents -- ...
引用是C++引入的新语言特性,是C++常用的一个重要内容之一,正确、灵活地使用引用,可以使程序简洁、高效。 引用简介 引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。 引用的声明方法:类型标识符 &引用名=目标变量名; :int a; int &ra=a; //定义引用ra,它是变量a...
函数存放在内存的代码区域内,它们同样有地址,我们如何能获得函数的地址呢? 假如我们有一个int test(int a)的函数,那么,它的地址就是函数的名字,这一点如同数组一样,数组的名字就是数组的起始地址。 !-- frame contents -- !-- /frame contents -- 定义一个指向函数的指针用如下的形式,以上面的test()为例: ...
就指向指针的指针,很早以前在说指针的时候说过,但后来发现很多人还是比较难以理解,这一次我们再次仔细说一说指向指针的指针! 先看下面的代码,注意看代码中的注解! //程序作者:管宁 //站点:www.cndev-lab.com //所有稿件均有版权,如要转载,请务必著名出处和作者 #include iostream #include string usingnamespacestd; voidprint_char(...
数据在内存的存放有以下几种形式 1.栈区--由编译器自动分配并且释放,该区域一般存放函数的参数值,局部变量的值等, 2.堆区--一般由程序员分配释放,如果程序员不释放,程序结束的时候才会被操作系统回收, 3.寄存器区--用来保存栈顶指针和指令指针 4.全局去--也是静态区,全局变量和静态变量都是存储在一起的,初始化的全局变量和静态变...

经验教程

136

收藏

20
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部