看懂IL代码

//示例一:输出整数的立方值。
private void PrintCube( int i )
{
    int cube = i * i * i;
    Console.WriteLine( cube );
}
//方法签名。
/** hidebysig:MethodAttributes 枚举值之一,指示此方法按名称和签名隐藏,否则只
/// 按名称隐藏。
/// cil managed:未查到具体资料,应是“受中间语言管理”之意。

.method private hidebysig instance void 
          PrintCube(int32 i) cil managed
  {
    // 代码大小       15 (0xf)
    .maxstack  2
    /**//**//** 在 .locals 部分声明所有的局部变量。
    .locals init ([0] int32 cube)    /**//**//** 第一个名局部变量,int 型,名为 cube。索
                                    /// 引从 0 开始。
    IL_0000:  nop    /**//**//** no operation.
    IL_0001:  ldarg.1    /**//**//** load argument 第一个方法参数入栈,比如“3”。索引号
                        /// 从 1 开始,而不是从 0 开始。
    IL_0002:  ldarg.1    /**//**//** 再次向堆栈压入第一个方法参数,又一个“3”。
    IL_0003:  mul    /**//**//** multiply 计算堆栈最顶上两个数的乘积 3×3,并把结果入栈,
                    /// 即堆栈最顶部是 9 了。
    IL_0004:  ldarg.1    /**//**//** 再次压入第一个方法参数“3”。
    IL_0005:  mul    /**//**//** 堆栈最顶上是“3”,第二是“9”,计算 3×9,此时 27 入栈。
    IL_0006:  stloc.0    /**//**//** pop value from stack to local variable 堆栈最顶上的
                        /// 值“27”出栈,并被赋给索引位置“0”处的局部变量 cube,
                        /// 即内存中变量 cube 的值为“27”。
    IL_0007:  ldloc.0    /**//**//** 局部变量 cube 的值“27”入栈。
    IL_0008:  call       void [mscorlib]System.Console::WriteLine(int32)
                        /**//**//** 控制台输出堆栈最顶上的 32 位整数“27”。
    IL_000d:  nop    /**//**//** no operation.
    IL_000e:  ret    /**//**//** return from method.
  } // end of method Program::PrintCube
//示例二:把字符串拆分成字符,并按顺序每行输出一个字符
public void SeparateString( string source )
{
    if( source == null )
        return;

    int count = source.Length;

    char c;
    for( int i = 0; i < count; i++ )
    {
        c = source[ i ];
        Console.WriteLine( c );
    }
}

.method public hidebysig instance void 
          SeparateString(string source) cil managed
  {
    // 代码大小       55 (0x37)
    .maxstack  2
    .locals init ([0] int32 count,
             [1] char c,
             [2] int32 i,
             [3] bool CS$4$0000)    /**//**//** 索引为“3”的这个布尔型局部变量在 C# 代
                                    /// 码中并未显式声明,是编译器编译时添加的,
                                    /// 用于保存执行过程中布尔运算的结果,比如比
                                    /// 较 source 是否为空时,以及比较 i<count 时。
    IL_0000:  nop
    IL_0001:  ldarg.1    /**//**//** 方法参数 source 的值入栈。
    IL_0002:  ldnull    /**//**//** “空引用”null入栈。
    IL_0003:  ceq    /**//**//** compare equal 比较栈顶的 null 和第二项的 source 是否相等,并
                    /// 把结果 0(false,source 不为空)或 1(true,source 为空)入栈。
    IL_0005:  ldc.i4.0    /**//**//** 32 位整型数“0”入栈。
    IL_0006:  ceq    /**//**//** 比较栈顶的“0”和堆栈的第二项,第二项可能是“0”,也可能
                    /// 是“1”。比较的结果“1”或“0”入栈。
    IL_0008:  stloc.3    /**//**//** 栈顶的“1”或“0”出栈,被保存到索引为“3”的局部变量中。
    IL_0009:  ldloc.3    /**//**//** 执行后,栈顶为“1”(source 不为空)或“0”(source 为空)。
    IL_000a:  brtrue.s   IL_000e    /**//**//** branch on non-false or non-null 判断栈顶是否
                                    /// 为“1”,如果是,跳转到第“IL_000e”行;否则
                                    /// 继续往下执行。

    IL_000c:  br.s       IL_0036    /**//**//** unconditional branch 当栈顶为“0”时,才会
                                    /// 执行到这一行,这一行的执行结果是程序无条件
                                    /// 跳转到第“IL_0036”行。

    IL_000e:  ldarg.1
    IL_000f:  callvirt   instance int32 [mscorlib]System.String::get_Length()    
                        /**//**//** 对堆栈最顶上的字符串调用其获取长度的实例方法,长度值被入栈。
                        /// “get_Length()”实际是字符串 Length 属性的“get”部分。
    IL_0014:  stloc.0    /**//**//** 局部变量 count 被赋值为字符串长度。
    IL_0015:  ldc.i4.0
    IL_0016:  stloc.2    /**//**//** 局部变量 i 被赋值为 0。
    IL_0017:  br.s       IL_002e    /**//**//** 无条件跳转到第“IL_002e”行。

    IL_0019:  nop
    IL_001a:  ldarg.1
    IL_001b:  ldloc.2
    IL_001c:  callvirt   instance char [mscorlib]System.String::get_Chars(int32)    
                        /**//**//** source 中索引为 i 处的 char 值入栈。
    IL_0021:  stloc.1
    IL_0022:  ldloc.1
    IL_0023:  call       void [mscorlib]System.Console::WriteLine(char)    /**//**//** char 值被输
                                                                        /// 出到控制台。
    IL_0028:  nop
    IL_0029:  nop
    IL_002a:  ldloc.2    /**//**//** i 值入栈。
    IL_002b:  ldc.i4.1    /**//**//** 32 位整数 1 入栈。
    IL_002c:  add    /**//**//** i+1 的结果入栈。
    IL_002d:  stloc.2    /**//**//** i=i+1。
    IL_002e:  ldloc.2    /**//**//** i 值入栈。
    IL_002f:  ldloc.0    /**//**//** count 值入栈。
    IL_0030:  clt    /**//**//** compare less than 比较 i<count 是否为真,比较结果入栈。
    IL_0032:  stloc.3
    IL_0033:  ldloc.3
    IL_0034:  brtrue.s   IL_0019    /**//**//** 如果 i<count 则跳转到第“IL_0019”行。

    IL_0036:  ret
  } // end of method Program::SeparateString


总结分析:

ldstr: 将对字符串的对象引用推送到堆栈上
 ldloc: 将变量的对象引用推送到堆栈上 
 idc.i4   idc.i8:   将4个字节的整数送到堆栈上,将超过32位的常数送到堆栈上
 stloc index: 从堆栈中弹出值并将其放到局部变量index中,index 从0向上编号
 newobj:初始化,调用构造函数,分配内存
 call,callvirt: call 根据引用类型的静态类型来调度方法,callvirt根据引用类型的动态类型来调度方法

 .ctor:构造函数,在类被实例化时,它会被自动调用。

 

 Example 1

class Program           
{         
  static void Main(string[] args)
            {           

       String s = "a";        
                  s = "abcd";           
            }         
}

 IL_0001: ldstr     "a"                   使用ldstr指令为字串对象“a”分配内存,并将此对象引用压入到线程堆栈中
  IL_0006:  stloc.0                           使用stloc指令从线程堆栈顶弹出先前压入的对象引用,将其传给局部变量s(其索引号为0)。
  IL_0007:  ldstr      "abcd"               使用ldstr指令为字串对象“abcd”分配内存,并将此对象引用压入到线程堆栈中
  IL_000c:  stloc.0                            使用stloc指令从线程堆栈顶弹出先前压入的对象引用,将其传给局部变量s(其索引号为0)。

 

 Example 2
(1)String s1 = "ab";          
        s1+="cd";
(2)String s1="ab"+"cd";
 
(1)
         IL_0001: ldstr     "ab"           
         IL_0006:  stloc.0
         IL_0007:  ldloc.0
         IL_0008:  ldstr      "cd"
         IL_000d:  call    string [mscorlib]System.String::Concat(string, string)
         IL_0012:  stloc.0
 (2)
        IL_0001: ldstr     "abcd"
         IL_0006:  stloc.0

可以很清楚地看到,第(1)段代码将导致String类的Concat()方法被调用(实现字串加法运算)。对于第(2)段代码,由于C#编译器聪明地在编译时直接将两个字串合并为一个字串字面量,所以程序运行时CLR只调用一次ldstr指令就完成了所有工作,其执行速度谁快就不言而喻了!

转载于:https://www.cnblogs.com/szjdw/archive/2011/10/27/2226808.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值