汇编的艺术(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
-------------------------------------------------------