您的位置:知识库 »

[你必须知道的.NET] 第十四回:认识IL代码---从开始到现在

作者: Anytao  来源: 博客园  发布时间: 2008-09-12 14:12  阅读: 4981 次  推荐: 0   原文链接   [收藏]  
[1] [你必须知道的.NET] 第十四回:认识IL代码---从开始到现在
[2] [你必须知道的.NET] 第十四回:认识IL代码---从开始到现在

系列文章导航:

[你必须知道的.NET] 开篇有益

[你必须知道的.NET] 第一回:恩怨情仇:is和as

[你必须知道的.NET] 第二回:对抽象编程:接口和抽象类

[你必须知道的.NET] 第三回:历史纠葛:特性和属性

[你必须知道的.NET] 第四回:后来居上:class和struct

[你必须知道的.NET] 第五回:深入浅出关键字---把new说透

[你必须知道的.NET] 第六回:深入浅出关键字---base和this

[你必须知道的.NET] 第七回:品味类型---从通用类型系统开始

[你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理

[你必须知道的.NET] 第九回:品味类型---值类型与引用类型(中)-规则无边

[你必须知道的.NET] 第十回:品味类型---值类型与引用类型(下)-应用征途

[你必须知道的.NET] 第十一回:参数之惑---传递的艺术(上)

[你必须知道的.NET] 第十二回:参数之惑---传递的艺术(下)

[你必须知道的.NET] 第十三回:从Hello, world开始认识IL

[你必须知道的.NET] 第十四回:认识IL代码---从开始到现在

[你必须知道的.NET] 第十五回:继承本质论

[你必须知道的.NET] 第十六回:深入浅出关键字---using全接触

[你必须知道的.NET] 第十七回:貌合神离:覆写和重载

[你必须知道的.NET] 第十八回:对象创建始末(上)

[你必须知道的.NET] 第十九回:对象创建始末(下)

[你必须知道的.NET]第二十回:学习方法论

[你必须知道的.NET]第二十一回:认识全面的null

[你必须知道的.NET]第二十二回:字符串驻留(上)---带着问题思考

[你必须知道的.NET]第三十二回,深入.NET 4.0之,Tuple一二


  3. 分析结构

  分析IL结构,就参阅《第十三回:从Hello, world开始认识IL》 ,已经有了大致的介绍,在此不需要进行过多的笔墨,实际上IL的本身的结构也不是很复杂,了解了大致的体系即可。

  4. 解析常用命令

  我们在了解了IL文件结构的基础上,通过学习常用的IL命令,就可以基本上对IL达到了了解不过分的标准,因此对IL常用命令的分析就是本文的重点和要点。我们通过对常用命令的解释、示例与分析,逐步了解你陌生的语言世界原来也很简单。

  IL指令集包括了基础指令集和对象模型指令集大概有近200多个,对我们来说消化这么多的陌生指令显然不是明智的办法,就行高级语言的关键字一样,我们只取其一瓢独饮,抓大放小的革命传统同样是有效的学习办法,详细的指令集解释请下载[MSIL指令速查手册]。

  4.1 newobj和initobj

  newobj和intiobj指令就像两个兄弟,常常让我们迷惑在其然而不知其所以然,虽然认识但是不怎么清楚,这种感觉很郁闷,下面就让我们看看他们的究竟:

代码引入


指令说明

深入分析

从上面的代码中,我们可以得出哪些值得推敲的结论呢?

MSDN给出的解释是:newobj用于分配和初始化对象;而initobj用于初始化值类型。


  那么newobj又是如何分配内存,完成对象初始化;而initobj又如何完成对值类型的初始化呢?

  显然,关于newobj指令,在《第五回:深入浅出关键字---把new说透》中,已经有了一定的介绍,简单说来关于newobj我们有如下结论:

  • 从托管堆分配指定类型所需要的全部内存空间。

  • 在调用执行构造函数初始化之前,首先初始化对象附加成员:一个是指向该类型方法表的指针;一个是SyncBlockIndex,用于进行线程同步。所有的对象都包含这两个附加成员,用于管理对象。

  • 最后才是调用构造函数ctor,进行初始化操作。并返回新建对象的引用地址。

  而initobj的作用又可以小结为:

  • 构造新的值类型,完成值类型初始化。值得关注的是,这种构造不需要调用值类型的构造函数。具体的执行过程呢?以上例来说,initobj MyStruct的执行结果是,将MyStruct中的引用类型初时化为null,而基元类型则置为0。

  因此,值类型的初始化可以是:

//initobj方式初始化值类型

initobj    Anytao.net.My_Must_net.IL.MyStruct

  同时,也可以直接显示调用构造函数来完成初始化,具体为

  MyStruct ms = new MyStruct(123);

  对应于IL则是对构造函数cto的调用。

//调用构造函数方式初始化值类型

call       instance void Anytao.net.My_Must_net.IL.MyStruct::.ctor(int32)

  • Initobj还用于完成设定对指定存储单元的指针置空(null)。这一操作虽不常见,但是应该引起注意。

  由此可见,newobj和initobj,都具有完成实例初始化的功能,但是针对的类型不同,执行的过程有异。其区别主要包括:

  • newobj用于分配和初始化对象;而initobj用于初始化值类型。因此,可以说,newobj在堆中分配内存,并完成初始化;而initobj则是对栈上已经分配好的内存,进行初始化即可,因此值类型在编译期已经在栈上分配好了内存。

  • newobj在初始化过程中会调用构造函数;而initobj不会调用构造函数,而是直接对实例置空。

  • newobj有内存分配的过程;而initobj则只完成数据初始化操作。

  关于对象的创建,还有其他的情况值得注意,例如:

  • Newarr指令用来创建一维从零起始的数组;而多维或非从零起始的一维数组,则仍由newobj指令创建。

  • String类型的创建由ldstr指令来完成,具体的讨论我们在下文来展开。

  4.2 call、callvirt和calli

  call、callvirt和calli指令用于完成方法调用,这些正是我们在IL中再熟悉不过的几个朋友。那么,同样是作为方法调用,这几位又有何区别呢?我们首先对其做以概括性的描述,再来通过代码与实例,进入深入分析层面。

  • call使用静态调度,也就是根据引用类型的静态类型来调度方法。

  • callvirt使用虚拟调度,也就是根据引用类型的动态类型来调度方法;

  • calli又称间接调用,是通过函数指针来执行方法调用;对应的直接调用当然就是前面的:call和callvirt。

  然而,虽然有以上的通用性结论,但是对于call和callvirt不可一概而论。call在某种情况下可以调用虚方法,而callvirt也可以调用非虚方法。具体的分析我们在以后的文章中来展开,暂不做过多分析。   

  5. 结论

  本文从几个重点的IL指令开始,力求通过对比性的分析和深入来逐步揭开IL的神秘与迷惑,正如我们在开始强调的那样,本文只是个开始也许也是个阶段,对IL的探求正如我自己的脚步一样,也在继续着,为的是在.NET的技术世界能够有更多的领悟。作者期望通过不断的努力逐渐和大家一起从IL世界探求.NET世界,在以后的讨论中我们间或的继续这个主题的不断成长。

                      ©2007 Anytao.com

[第1页][第2页]
0
0
标签:.NET IL

热门文章

    最新文章

      最新新闻

        热门新闻