我们知道 在.net中引用类型不加ref传参传递的是对象的地址,而加ref传参传递的是变量的地址,在操作中两种传参的方式效果是一样的,下面就有几个问题了
1. 这个相同的效果是怎么实现的呢?
2. 方法接受的参数一个是对象的地址,一个是变量的地址,最终都操作了堆中的对象,这是怎么实现的呢?
写一个简单的例子:
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
3
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
5
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
6
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
7
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
9
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
10
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
11
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
12
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
13
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
14
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
15
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
16
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
17
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
18
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
19
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
20
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
21
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
22
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
23
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
24
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
25
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
26
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
下面是调试得到的部分汇编代码:
Hello h = new Hello();
mov ecx,98309Ch
call FF931FAC
mov dword ptr [ebp-4Ch],eax
mov ecx,dword ptr [ebp-4Ch]
call FF94BFC8
mov eax,dword ptr [ebp-4Ch] //将对象的地址赋值给eax寄存器
mov dword ptr [ebp-44h],eax //将eax寄存器的值赋值给栈上的h变量
p.T( h);
mov edx,dword ptr [ebp-44h] //将h变量的值赋值给edx寄存器
mov ecx,dword ptr [ebp-40h] //这一句不是很理解,推测是和下面的cmp命令结合使用,使下四个字节的内存可以使用,望高人来解答
cmp dword ptr [ecx],ecx
call FF94BFA8 //调用方法
nop
下面是调用的方法的汇编:
public void T( Hello h)
{
push ebp
mov ebp,esp
push edi
push esi
push ebx
sub esp,34h
xor eax,eax
mov dword ptr [ebp-10h],eax
xor eax,eax
mov dword ptr [ebp-1Ch],eax
mov dword ptr [ebp-3Ch],ecx //同上,望高人解答。
mov dword ptr [ebp-40h],edx //将edx寄存器的值,也就是h变量中的值放到ebp-40这个地址的地方
cmp dword ptr ds:[00982E14h],0
je 00000027
call 7908A2C1
nop
h.HHH = 10000;
mov eax,dword ptr [ebp-40h] //将h变量的值赋值给寄存器eax,这样eax就得到了对象在堆中的地址
mov dword ptr [eax+4],2710h //给HHH赋值
h.BBB = 10;
mov eax,dword ptr [ebp-40h] //同上,将h变量的值赋值给寄存器eax,这样eax就得到了对象在堆中的地址
mov dword ptr [eax+8],0Ah //给BBB赋值
}
下面是引用类型用ref传参的分析:
代码:
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
3
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
5
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
6
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
7
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
9
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
10
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
11
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
12
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
13
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
14
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
15
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
16
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
17
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
18
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
19
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
20
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
21
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
22
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
23
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
24
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
25
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
26
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
27
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
28
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
29
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
下面是调试得到的部分汇编代码:
Hello h = new Hello();
mov ecx,98309Ch
call FF931FAC
mov dword ptr [ebp-4Ch],eax
mov ecx,dword ptr [ebp-4Ch]
call FF94BFC8
mov eax,dword ptr [ebp-4Ch]
mov dword ptr [ebp-44h],eax
p.T(ref h);
lea edx,[ebp-44h] //lea命令直接将ebp-44h这个地址存到edx寄存器,这是h变量在栈上的地址。
mov ecx,dword ptr [ebp-40h] //用上,望高人解答
cmp dword ptr [ecx],ecx
call FF94BFA8
nop
下面的方法执行时的汇编:
public void T(ref Hello h)
{
push ebp
mov ebp,esp
push edi
push esi
push ebx
sub esp,34h
xor eax,eax
mov dword ptr [ebp-10h],eax
xor eax,eax
mov dword ptr [ebp-1Ch],eax
mov dword ptr [ebp-3Ch],ecx
mov dword ptr [ebp-40h],edx //将edx寄存器的值,也就是h变量的地址放到ebp-40这个地址的地方
cmp dword ptr ds:[00982E14h],0
je 00000027
call 7908A2C9
nop
h.HHH = 10000;
mov eax,dword ptr [ebp-40h] //这里ptr [ebp-40h] 对应的是h变量的地址
mov eax,dword ptr [eax] //h变量的值也就是对象在堆上的地址赋值给eax寄存器
mov dword ptr [eax+4],2710h //给HHH赋值10000
h.BBB = 10;
mov eax,dword ptr [ebp-40h]
mov eax,dword ptr [eax]
mov dword ptr [eax+8],0Ah //给BBB赋值10
}
总结:
在引用类型用ref传递参数的时候,编译器在会在方法内部,增加一个指向过程,得到传递进来的变量地址所对应的变量值,这样就和
引用类型不加ref传递参数得到了相同的结果,在方法内部的操作,也得到相同的结果。
本人对汇编也不是很了解,可能有不正确的地方,希望高人能指点。
拜谢~~~