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


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

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

    拜谢~~~

     

  • 相关阅读:
    mysql表设计的一些面试题
    sqlserver统一给所有表添加字段
    领域知识层次
    3年经验的java程序员面试应该具备的基本技能
    bootstraptable前端分页
    could not find setter for
    el-table表格单选按钮
    use of the same entity name twice
    《CSS核心技术详解》
    遇见未知的CSS
  • 原文地址:https://www.cnblogs.com/Jonas/p/1456580.html
Copyright © 2020-2023  润新知