C/C++的参数传递机制(二)

2015-01-25 19:28:09 · 作者: · 浏览: 23
下面来看一下Test001函数对应的反汇编代码的参数传递
?
?
__int64* _pArray = NULL;
004137E0 ?mov ? ? ? ? dword ptr [_pArray],0?
// Test the pointer?
GetMemory(_pArray);
00413812 ?mov ? ? ? ? eax,dword ptr [_pArray]?
00413815 ?push ? ? ? ?eax ?
00413816 ?call ? ? ? ?GetMemory (411203h)?
0041381B ?add ? ? ? ? esp,4?
?
从上面的汇编代码可以看出,其实是0被压入到栈中作为参数,所以GetMemory(_pArray)无论做什么事,其实都与指针变量_pArray无关。GetMemory()分配的空间是让栈中的临时变量指向的,当函数退出时,栈得到恢复,结果申请的空间没有人管,就产生内存泄露的问题了。《C++ Primer》将参数传递分为引用传递和非引用传递两种,非引用传递其实可以理解为值传递。这样看来,指针传递在某种意义上也是值传递,因为传递的是指针的值(1个4BYTE的值)。值传递都不会改变传入实参的值的。而且普通的指针传递其实是改变的指针变量指向的内容。
?
下面再看一下Test002函数对应的反汇编代码的参数传递
?
__int64* _pArray = NULL;
004137E0 ?mov ? ? ? ? dword ptr [_pArray],0?
GetMemory(&_pArray);
004137E7 ?lea ? ? ? ? eax,[_pArray]?
004137EA ?push ? ? ? ?eax ?
004137EB ?call ? ? ? ?GetMemory (4111FEh)?
?
004137F0 ?add ? ? ? ? esp,4?
?
从上面的汇编代码lea eax,[_pArray] 可以看出,_pArray的地址被压入到栈中去了。
?
然后看一看GetMemory(&_pArray)的实现汇编代码。
?
? ?0x0040159b <+0>: ? ? ? ?push ? ebp
?
? ?0x0040159c <+1>: ? ? ? ?mov ? ?ebp,esp
?
? ?0x0040159e <+3>: ? ? ? ?sub ? ?esp,0x18
?
? ?0x004015a1 <+6>: ? ? ? ?mov ? ?DWORD PTR [esp],0x20
?
? ?0x004015a8 <+13>: ? ? ? ?call ? 0x473ef0 <_Znaj>
?
? ?0x004015ad <+18>: ? ? ? ?mov ? ?edx,DWORD PTR [ebp+0x8]
?
? ?0x004015b0 <+21>: ? ? ? ?mov ? ?DWORD PTR [edx],eax
?
? ?0x004015b2 <+23>: ? ? ? ?leave?
?
? ?0x004015b3 <+24>: ? ? ? ?ret ?
?
蓝色的代码是分配临时变量空间,然后调用分配空间函数分配空间,得到的空间指针即eax.
?
然后红色的汇编代码即从ebp+0x8的栈上取到上面压入栈中的参数_pArray的地址.
?
mov DWORD PTR [edx],eax即相当于把分配的空间指针eax让edx指向,也即让_pArray指向分配的空间eax.
?
总之,无论是哪种参数传递方式,参数都是通过栈上的临时变量来间接参与到被调用函数的。指针作为参数,其本身的值是不可能被改变的,能够改变的是其指向的内容。引用是通过指针来实现的,所以引用和指针在效率上一样的。