第二章 传参
下面我们来讨论传参的情况:
在参数传递的过程中,有一个动作是必然会发生的,这就是从实参到形参的拷贝。
在值传递过程中,拷贝的是变量的值(如有必要,调用拷贝构造函数)。
在指针传递过程中,拷贝的则是指针的值,也就是所指向变量的地址。
在引用过程中,拷贝的是引用所在内存中的值,其实也就是上文所说的常指针的值,总之拷贝的是个地址。
而在函数内部,对拷贝进来的这个值的任何改变都不影响外部数据。而对指针所指变量或引用所表示的变量,则可能会有修改。
如第一章所说的,其实指针和引用也是值的一种,传指针和传引用本质上都是值传递的方式,只不过传指针和传引用所传递的是一个地址值。
网上有些文章明确指出“指针传递参数和引用传递参数是有本质上的不同的”,对此我只能认为文章作者对引用的本质(包括引用在内存中的存在和表现方式以及对引用的访问等细节)没弄清楚。最好的明辨是非的方法是读者自己动手做一下,然后查看内存和反汇编。
测试代码:
void Func(int n, int *pN, int& nRef){}
void main()
{
int n = 10;
int* pN = &n;
int& nRef = n;
Func( n, pN, n);
Func( n, pN, nRef);
}
反汇编代码:
int n = 10;
0041143E mov dword ptr [n],0Ah
int* pN = &n;
00411445 lea eax,[n]
00411448 mov dword ptr [pN],eax
int& nRef = n; //引用的初始化
0041144B lea eax,[n] //将整形变量n的地址放入eax,
0041144E mov dword ptr [nRef],eax //再将eax的值放入nRef代表的内存单元
Func( n, pN, n); //参数是从右往左压栈,此句是把整型值做int&传入
00411451 lea eax,[n] //此处应该是将n做int&压栈
00411454 push eax //我们可以清楚的看到,压入的数据是n的地址(lea)
00411455 mov ecx,dword ptr [pN] //压入指针值
00411458 push ecx
00411459 mov edx,dword ptr [n] //压入整型值n
0041145C push edx
0041145D call Func (4111E5h)
00411462 add esp,0Ch
Func( n, pN, nRef); //参数是从右往左压栈
00411465 mov eax,dword ptr [nRef] //压入引用值,由上文引用的初始化处可知,
00411468 push eax //此处压入的其实同样是n的地址,只不过这个地址
//不是通过eax取出来的,而是存储在nRef内存区域
00411469 mov ecx,dword ptr [pN]
0041146C push ecx
0041146D mov edx,dword ptr [n]
00411470 push edx
00411471 call Func (4111E5h)
00411476 add esp,0Ch