引用类型传参问题的深入分析

我们知道 .net中引用类型不加ref传参传递的是对象的地址,而加ref传参传递的是变量的地址,在操作中两种传参的方式效果是一样的,下面就有几个问题了

1. 这个相同的效果是怎么实现的呢?

2. 方法接受的参数一个是对象的地址,一个是变量的地址,最终都操作了堆中的对象,这是怎么实现的呢?

写一个简单的例子:

 

Code

下面是调试得到的部分汇编代码:

            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传参的分析:

代码:

 

Code

下面是调试得到的部分汇编代码:

 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传递参数得到了相同的结果,在方法内部的操作,也得到相同的结果。

本人对汇编也不是很了解,可能有不正确的地方,希望高人能指点。

拜谢~~~

 

原文地址:https://www.cnblogs.com/Jonas/p/1456580.html