zoukankan      html  css  js  c++  java
  • 汇编的艺术(02)& operator

    首先看一段代码:

    void calc(int &a)
    {
        a += 10;
    }
    
    int main()
    {
        int a = 0;
        calc(a);
        printf("%d\n", a);
        return 0;
    }

    答案输出 a = 10 以前有种疑惑,为什么没有把a的地址传进去,也能够改变a的值。

    事实上,这些工作都交给编译器做了,下面看反汇编代码:

    void calc(int &a)
    {
        a += 10;
    00000000  push        ebp  
    00000001  mov         ebp,esp 
    00000003  push        eax  
    00000004  mov         dword ptr [ebp-4],ecx 
    00000007  cmp         dword ptr ds:[00342E14h],0 
    0000000e  je          00000015 
    00000010  call        72393B89 
    00000015  mov         eax,dword ptr [ebp-4] 
    00000018  add         dword ptr [eax],0Ah 
    }
    0000001b  nop              
    0000001c  mov         esp,ebp 
    0000001e  pop         ebp  
    0000001f  ret  
    
    int main()
    {
        int a = 0;
    00000000  push        ebp  
    00000001  mov         ebp,esp 
    00000003  sub         esp,8 
    00000006  cmp         dword ptr ds:[00342E14h],0 
    0000000d  je          00000014 
    0000000f  call        72393BE9 
    00000014  xor         edx,edx 
    00000016  mov         dword ptr [ebp-4],edx 
    00000019  xor         edx,edx 
    0000001b  mov         dword ptr [ebp-4],edx 
    0000001e  xor         edx,edx 
    00000020  mov         dword ptr [ebp-8],edx 
        calc(a);
    00000023  lea         ecx,[ebp-8] 
    00000026  call        dword ptr ds:[003435F8h] 

    注意几行红色的汇编代码,编译器对calc(a)进行的一定程度上的优化,把a的地址直接传给ecx,然后再利用这个地址对a进行操作。

    其实到这里问题就明朗了:int &a = b; a是b的一个引用,a就是b,只不过换了一个马甲而已。

    所以:引用总是指向一个是实例化的对象,这点和指针还是有点差别的,比如下面的代码:

    int main()
    {
        char a = 1;
        char &b = a;
        char* p = &a;
        b += 1;
        printf("%d %d\n", sizeof(b), sizeof(p));
        return 0;
    }

    先思考,b这个引用在栈中是否开辟了空间呢?如果开辟了栈空间给b,那么b和p又有什么样的区别呢?

    int main()
    {
        char a = 1;
    00000000  push        ebp  
    00000001  mov         ebp,esp 
    00000003  sub         esp,10h 
    00000006  cmp         dword ptr ds:[00352E14h],0 
    0000000d  je          00000014 
    0000000f  call        72513BE9 
    00000014  xor         edx,edx 
    00000016  mov         dword ptr [ebp-4],edx 
    00000019  xor         edx,edx 
    0000001b  mov         dword ptr [ebp-8],edx 
    0000001e  xor         edx,edx 
    00000020  mov         dword ptr [ebp-0Ch],edx 
    00000023  xor         edx,edx 
    00000025  mov         dword ptr [ebp-4],edx 
    00000028  mov         dword ptr [ebp-10h],1 
        char &b = a;
    0000002f  lea         eax,[ebp-10h] 
    00000032  mov         dword ptr [ebp-8],eax 
        char* p = &a;
    00000035  lea         eax,[ebp-10h] 
    00000038  mov         dword ptr [ebp-0Ch],eax 
        b += 1;
    0000003b  mov         eax,dword ptr [ebp-8] 
    0000003e  inc         byte ptr [eax] 
        printf("%d %d\n", sizeof(b), sizeof(p));
    00000040  push        0B94194h 
    00000045  push        1    
    00000047  push        4    
    00000049  push        2C4D00h 
    0000004e  call        FFDC31C4 
    00000053  add         esp,10h 
    00000056  nop              
        return 0;

    通过上面的反汇编代码,可以观察出来,b和p在堆栈中是没有本质区别的 char &b = a, char *p = &a的反汇编代码是一样的。

    并且,b和p是一样的在栈中开辟了空间。但是用sizeof(b)和sizeof(p)区别就出来了,一个是字节大小,一个是指针大小。

    通过上面其实也可以得出结论,引用的操作都是由编译器来完成的,引用只不过是实体变量的一个马甲而已。

    -------------------------------------------------------

    kedebug

    Department of Computer Science and Engineering,

    Shanghai Jiao Tong University

    E-mail: kedebug0@gmail.com

    GitHub: http://github.com/kedebug

    -------------------------------------------------------

  • 相关阅读:
    FTP解决办法:服务器发回了不可路由的地址。使用服务器地址代替。
    隐藏显示终端的光标(shell echo,linux c printf)
    FTP服务2种工作方式详解,PORT方式和PASV方式,(即主动模式和被动模式)
    XP使用VNC远程桌面CentOS 6(原创,备忘)
    LINUX命令行技巧
    FTP服务器(vsftpd)配置随笔
    更快、更强 64位编程的三十二条军规
    MFC 程序入口和执行流程
    css实现居中
    treeview控件显示指定目录下的目录和文件
  • 原文地址:https://www.cnblogs.com/kedebug/p/2812797.html
Copyright © 2011-2022 走看看