} } }

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

    添加时间:2013-5-5 点击量:

    在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只是存储了本身存储空间的偏移地址,也就是传地址
    calladd@@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
    calladd@@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


    可以看到,指针和引用的汇编码一样,是以两者的感化也一样


    无论对感情还是对生活,“只要甜不要苦”都是任性而孩子气的,因为我们也不完美,我们也会伤害人。正因为我们都不完美,也因为生活从不是事事如意,所以对这些“瑕疵”的收纳才让我们对生活、对他人的爱变得日益真实而具体。—— 汪冰《世界再亏欠你,也要敢于拥抱幸福》
    分享到: