C/C++的参数传递机制

发表于:2015-1-19 10:09

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:飞鹤0755    来源:51Testing软件测试网采编

分享:
  通过上面的反汇编代码,我们可以看出指针传递和引用传递在机制是一样的,都是将指针值(即地址)压入栈中,调用函数,然后恢复栈。Swap(nA, nB)和Swap(&nA, &nB);在实际上的汇编代码也基本上一模一样,都是从栈中取出地址来。由此可以看出引用和指针在效率上是一样的。这也是为什么指针和引用都可以达到多态的效果。指针传递和引用传递其实都是改变的地址指向的内存上的值来达到修改参数的效果。
  值传递
  下面是值传递对应的反汇编代码
  // Test to pass by value
  SetValue(nA);
  0041374A  mov         eax,dword ptr [ebp-8]
  0041374D  push        eax
  0041374E  mov         ecx,dword ptr [nA]
  00413751  push        ecx
  00413752  call        SetValue (4111EAh)
  00413757  add         esp,8
  因为我的机器是32位的CPU,从上面的汇编代码可以看64Bit的变量被分成2个32Bit的参数压入栈中。这也是我们常说的,值传递会形成一个拷贝。如果是一个自定义的结构类型,并且有很多参数,那么如果用值传递,这个结构体将被分割为非常多个32Bit的逐个拷贝到栈中去,这样的参数传递效率是非常慢的。所以结构体等自定义类型,都使用引用传递,如果不希望别人修改结构体变量,可以加上const修饰,如(const MY_STRUCT&  _value);
  下面来看一下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.
  总之,无论是哪种参数传递方式,参数都是通过栈上的临时变量来间接参与到被调用函数的。指针作为参数,其本身的值是不可能被改变的,能够改变的是其指向的内容。引用是通过指针来实现的,所以引用和指针在效率上一样的。
22/2<12
春暖花开更文季,点击参与还有惊喜礼品~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计

法律顾问:上海漕溪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2023
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号