.NET IL代码

前言

IL是什么?
Intermediate Language (IL)微软中间语言

C#代码编译过程?
如下图
在这里插入图片描述
LC编译器:无论是VB code还是C# code都会被Language Compiler转换为MSIL(元数据和中间语言指令);

JIT编译器:根据系统环境将MSIL中间语言指令转换为机器码

为什么要了解IL代码?

如果想学好.NET,IL是必须的基础,IL代码是.NET运行的基础,当我们对运行结果有异议的时候,可以通过IL代码透过表面看本质;

IL也是更好理解、认识CLR的基础;

大量的实例分析是以IL为基础的,所以了解IL,是读懂他人代码的必备基础,同时自己也可以获得潜移默化的提高;

一、如何把ILDasm导入到VS中

首先找到ildasm.exe(我的路径):
在这里插入图片描述
在VS,工具—外部工具,添加一个:

在这里插入图片描述
效果:
在这里插入图片描述
在这里插入图片描述
符号及其含义:
在这里插入图片描述

二、分析IL代码

快速搜索IL指令对应含义demo

1.部分概念

Managed Heap(托管堆):这就是NET中的托管堆,用来存放引用类型,它是由GC(垃圾回收器自动进行回收)管理;

Call Stack(调用堆栈):调用堆栈:调用堆栈是一个方法列表,按调用顺序保存所有在运行期被调用的方法。

Evaluation Stack(计算堆栈):每个线程都有自己的线程栈,IL 里面的任何计算,都发生在 Evaluation Stack 上,其实就是一个 Stack 结构。可以 Push,也可以 Pop。(计算完后就只剩就算后的数据。)

Record Frame(局部变量表)

2.VS代码

代码如下(示例):

using System;

namespace 字符串转换
{
    class Program
    {
        static void Main(string[] args)
        {
            string test = "hello word";
            char[] c = test.ToCharArray();
            byte[] b = new byte[c.Length];
            for (int i = 0; i < c.Length; i++)
            {
                b[i] = Convert.ToByte(c[i]);
                Console.WriteLine("{0:X}    {1}", b[i],c[i]);
            }
            Console.ReadKey();
        }
    }
}

3.IL指令

代码如下(示例):
内部存在循环,注释以第一个循环的备注

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // 代码大小       90 (0x5a)
  .maxstack  4
  .locals init ([0] string test,
           [1] char[] c,
           [2] uint8[] b,
           [3] int32 i,
           [4] bool V_4)//定义 参数 test,c,b,i,V_4(此时已经把他们存入了Call Stack中的Record Frame中)
  IL_0000:  nop												//占位符
  IL_0001:  ldstr      "hello word"							//把字符串"hello word"压入计算栈中
  IL_0006:  stloc.0											//从计算栈的顶部弹出"hello word"并将其存储到索引 0 处的局部变量列表中V_0位置
  IL_0007:  ldloc.0											//将索引 0 处的局部变量加载到计算堆栈上
  IL_0008:  callvirt   instance char[] [mscorlib]System.String::ToCharArray()//调用转成数组方法
  IL_000d:  stloc.1											//从计算栈的顶部弹出数组并将其存储到索引 1处的局部变量列表中V_1位置
  IL_000e:  ldloc.1											//将索引 1 处的局部变量数组加载到计算堆栈上
  IL_000f:  ldlen											//将从零开始数组的元素的数目推送到计算堆栈上
  IL_0010:  conv.i4											//将位于计算堆栈顶部的值(数组的元素的数目)转换为 int32
  IL_0011:  newarr     [mscorlib]System.Byte				//将对新的维数组(Byte)的对象引用推送到计算堆栈上
  IL_0016:  stloc.2											//从计算栈的顶部弹出新数组并将其存储到索引 2处的局部变量列表中V_2位置
  IL_0017:  ldc.i4.0										//将整数值 0 作为 int32 推送到计算堆栈上
  IL_0018:  stloc.3											//从计算栈的顶部弹出0并将其存储到索引 3处的局部变量列表中V_3位置
  IL_0019:  br.s       IL_0047								//跳转到指令IL_0047								
  IL_001b:  nop
  IL_001c:  ldloc.2											//将局部变量(Byte数组)加载到计算堆栈上
  IL_001d:  ldloc.3											//将局部变量0加载到计算堆栈上
  IL_001e:  ldloc.1											//将局部变量(字符数组)加载到计算堆栈上
  IL_001f:  ldloc.3											//将局部变量0加载到计算堆栈上
  IL_0020:  ldelem.u2										//将字符数组[0]处加载到计算堆栈上
  IL_0021:  call       uint8 [mscorlib]System.Convert::ToByte(char)//对字符数组[0]调用ToByte函数
  IL_0026:  stelem.i1										//用转换后的byte值替换给定索引处的数组元素。
  IL_0027:  ldstr      "{0:X}    {1}"						//把字符串"{0:X}    {1}"压入计算栈中
  IL_002c:  ldloc.2											//将局部变量(Byte数组)加载到计算堆栈上(当前Byte数组[0]已更新)
  IL_002d:  ldloc.3											//将局部变量0加载到计算堆栈上
  IL_002e:  ldelem.u1										//将Byte数组[0]处加载到计算堆栈上
  IL_002f:  box        [mscorlib]System.Byte				//转换为引用类型
  IL_0034:  ldloc.1											//将局部变量(字符数组)加载到计算堆栈上
  IL_0035:  ldloc.3											//将局部变量0加载到计算堆栈上
  IL_0036:  ldelem.u2										//将字符数组[0]处加载到计算堆栈上
  IL_0037:  box        [mscorlib]System.Char				//转换为引用类型,数据存放入托管堆,计算栈上存放数据的引用。
  IL_003c:  call       void [mscorlib]System.Console::WriteLine(string,//调用WriteLine(string, object,object)
                                                                object,//根据计算栈中的数据为:
                                                                object)//"{0:X}    {1}" ,	Byte数组[0]引用,	字符数组[0]引用			
  IL_0041:  nop
  IL_0042:  nop
  IL_0043:  ldloc.3											//将局部变量0加载到计算堆栈上
  IL_0044:  ldc.i4.1										//将整数1加载到计算栈上
  IL_0045:  add												//相加(此处为循环时的++)
  IL_0046:  stloc.3											//弹出相加得到的1并压入局部变量V-3处。(替换了原来的0,一个循环结束)
  IL_0047:  ldloc.3											//将索引 3 处的局部变量加载到计算堆栈上
  IL_0048:  ldloc.1											//将索引 1 处的局部变量数组加载到计算堆栈上
  IL_0049:  ldlen											//将数组的元素的数目推送到计算堆栈上
  IL_004a:  conv.i4											//将位于计算堆栈顶部的值数组的元素的数目转换为 int32。
  IL_004b:  clt												//比较索引 3 处的局部变量与索引 1 处的局部变量数组元素个数,如果第一个值小于第二个值,则将整数值 1 (int32) 推送到计算堆栈上;反之,将 0 (int32) 推送到计算堆栈上。
  IL_004d:  stloc.s    V_4									//从计算堆栈的顶部弹出当前值(判断值)并将其存储在局部变量列表中的 V_4 处(Init处定义的变量)。
  IL_004f:  ldloc.s    V_4									//将V_4加载到计算堆栈上。
  IL_0051:  brtrue.s   IL_001b								//如果 value 为 true、非空或非零,则跳转到IL_001b
  IL_0053:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()//ReadKey函数调用
  IL_0058:  pop												//移除当前位于计算堆栈顶部的值
  IL_0059:  ret												//当前方法返回
} // end of method Program::Main

4.结果截图

在这里插入图片描述

参考链接:

https://www.cnblogs.com/yinrq/p/5486103.html
https://docs.microsoft.com/zh-tw/previous-versions/dd229210(v=msdn.10)?redirectedfrom=MSDN
https://www.cnblogs.com/zery/p/3366175.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值