汇编的艺术(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)区别就出来了,一个是字节大小,一个是指针大小。

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

 

posted @ 2012-12-11 13:53  kedebug  阅读(300)  评论(0编辑  收藏  举报