找回密码
 注册
搜索
热搜: 回贴
  • 前程无忧官网首页 有什么好的平台可以
  • 最新的销售平台 互联网营销的平台有哪
  • 制作网页的基本流程 网页制作和网页设
  • 【帝国CMS】输出带序号的列表(数字排
  • 网站建设公司 三一,中联,极东泵车的
  • 织梦 建站 织梦网站模版后台怎么更改
  • 云服务官网 哪些网站有免费的简历模板
  • 如何建网站要什么条件 建网站要用什么
  • 吉林市移动公司电话 吉林省退休人员网
  • 设计类毕业论文 网站设计与实现毕业论
查看: 347|回复: 7

IL代码底层运行机制之循环处理

[复制链接]
发表于 2009-3-16 20:30:17 | 显示全部楼层 |阅读模式 IP:江苏扬州
在这篇文章里,我们将讨论IL代码是怎样处理C#中的循环。例子还涉及到数组处理,以及一些新涉及到的指令。虽然已经有人进行过相关问题的研究,我也看过几篇有关文章,不过我认为他们描述得并不是很清楚,所以在这里我借机重新整理成文,希望对大家学习理解。net会有所帮助,同时也希望对研究虚拟机机制的有关设计人员有所帮助。
 
  同样,这里也先给出C#代码,然后再让我们详细研究其编译后的IL代码。下面是C#代码,它含有三个循环,分别是for、while、foreach循环:
 
public int LoopTest()
{
       int i=3;
       int j=9;
       int s=0;
       int k;                            file://以上各条语句定义变量并进行初始化

       for(k=0;k<=i;k++)
       {
              s+=k;
       }                                 file://for循环块
       k=0;

       while(k<j)
       {
              s+=k;
              k++;
       }                                 file://while循环块

       int[] array={2,3,4,5,6,7,8,9};
       foreach(int a in array)
       {
              s+=a;
       }                                 file://foreach循环块
       return s;
}
在这里,我们要做的是搞清楚C#编译器是把源程序翻译成怎样的IL代码以实现循环处理的,或者说如何用IL语言实现C#语言中的循环。这对我们深入理解C#语言特性是很有帮助的。当然仅仅这一点还不够,以后我还会介绍更多的有关方面的问题。
       首先让我们看看这个函数被编译成什么样的IL代码:
.method public hidebysig instance int32  LoopTest() cil managed
{
  // 代码大小       101 (0x65)
  .maxstack  3
  .locals init ([0] int32 i,
           [1] int32 j,
           [2] int32 s,
           [3] int32 k,
           [4] int32[] 'array',
           [5] int32 a,
           [6] int32 CS$00000003$00000000,
           file://跟函数返回值类型相同的局部变量,由编译器维护,专门用于存储返回
//值。如果函数为void型,则无此变量。
          [7] int32[] CS$00000007$00000001,
                 file://局部变量,存储数组引用,用于foreach循环。本例中对应‘array’数组。
           [8] int32 CS$00000008$00000002
              file://局部变量,存储数组索引。专用于foreach循环,由编译器维护。
         )
  IL_0000:  ldc.i4.3
  IL_0001:  stloc.0
  IL_0002:  ldc.i4.s   9
  IL_0004:  stloc.1
  IL_0005:  ldc.i4.0
  IL_0006:  stloc.2
  IL_0007:  ldc.i4.0
  IL_0008:  stloc.3
  IL_0009:  br.s       IL_0013
  IL_000b:  ldloc.2
  IL_000c:  ldloc.3
  IL_000d:  add
  IL_000e:  stloc.2
  IL_000f:  ldloc.3
  IL_0010:  ldc.i4.1
  IL_0011:  add
  IL_0012:  stloc.3
  IL_0013:  ldloc.3
  IL_0014:  ldloc.0
  IL_0015:  ble.s      IL_000b
  IL_0017:  ldc.i4.0
  IL_0018:  stloc.3
  IL_0019:  br.s       IL_0023
  IL_001b:  ldloc.2
  IL_001c:  ldloc.3
  IL_001d:  add
  IL_001e:  stloc.2
  IL_001f:  ldloc.3
  IL_0020:  ldc.i4.1
  IL_0021:  add
  IL_0022:  stloc.3
  IL_0023:  ldloc.3
  IL_0024:  ldloc.1
  IL_0025:  blt.s      IL_001b
  IL_0027:  ldc.i4.8
  IL_0028:  newarr     [mscorlib]System.Int32
  file://创建长度为8的System.Int32数组。可以看出数组元素被映射到Int32类对象。
  IL_002d:  dup
  IL_002e: ldtoken field valuetype '<PrivateImplementationDetails>'/'$$struct0x6000002-1'
                '<PrivateImplementationDetails>'::'$$method0x6000002-1'
  IL_0033: call void [mscorlib] System.Runtime.CompilerServices.RuntimeHelpers::
                 InitializeArray(class[mscorlib]System.Array, valuetype  [mscorlib] System.RuntimeFieldHandle)
  IL_0038:  stloc.s    'array'
  IL_003a:  ldloc.s    'array'
  IL_003c:  stloc.s    CS$00000007$00000001
  IL_003e:  ldc.i4.0
  IL_003f:  stloc.s    CS$00000008$00000002
  IL_0041:  br.s       IL_0055
  IL_0043:  ldloc.s    CS$00000007$00000001
  IL_0045:  ldloc.s    CS$00000008$00000002
  IL_0047:  ldelem.i4
  IL_0048:  stloc.s    a
  IL_004a:  ldloc.2
  IL_004b:  ldloc.s    a
  IL_004d:  add
  IL_004e:  stloc.2
  IL_004f:  ldloc.s    CS$00000008$00000002
  IL_0051:  ldc.i4.1
  IL_0052:  add
  IL_0053:  stloc.s    CS$00000008$00000002
  IL_0055:  ldloc.s    CS$00000008$00000002
  IL_0057:  ldloc.s    CS$00000007$00000001
  IL_0059:  ldlen
  IL_005a:  conv.i4
  IL_005b:  blt.s      IL_0043
  IL_005d:  ldloc.2
  IL_005e:  stloc.s    CS$00000003$00000000
  IL_0060:  br.s       IL_0062
  IL_0062:  ldloc.s    CS$00000003$00000000
  IL_0064:  ret
} // end of method Advanced::LoopTest
关于函数话题如.locals init语句等,请参见文章〈函数相关〉。这里我对其中的一些指令做出解释,主要是与本文相关的条件转移指令(b*.s)等。其他指令以后我会作适当的介绍。如下所示:
      指令          意义       记忆方法(*)
   br.s绝对跳转,相当于jmp

   blt.s小于转  Lower Than
   ble.s小于等于转  Lower or Equals
   ldlen取得数组长度
   ldelem.i4根据索引取得数组项


这里我们可以看到 .locals init伪指令给出了同源程序相同变量名称。这是因为在反汇编时,相同目录下有调试信息文件(*.pdb),否则的我们看到的结果变量以V_x形式(如V_1、V_2等)表示。有关函数局部变量的话题,请参见《函数相关》一文。
       如果你有WIN32汇编程序设计经验,可能都熟悉怎样实现循环控制。
发表于 2009-10-31 05:05:02 | 显示全部楼层 IP:澳大利亚
不要见一个爱一个,爱的太多,你的爱就要贬值。
回复

使用道具 举报

发表于 2009-11-23 14:05:02 | 显示全部楼层 IP:澳大利亚
今天没事来逛逛,看了一下,感觉相当的不错。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|小黑屋|最新主题|手机版|微赢网络技术论坛 ( 苏ICP备08020429号 )

GMT+8, 2024-9-30 15:24 , Processed in 0.197105 second(s), 14 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表