频道栏目
读书频道 > 软件开发 > C# > 精通C# : 第6版
1.4.1 CIL的作用
2013-06-22 10:09:40     我来说两句
收藏   我要投稿

本文所属图书 > 精通C# : 第6版

本书是C# 领域久负盛名的经典著作,深入全面地讲解了C# 编程语言和.NET 平台的核心内容,并结合大量示例剖析相关概念。全书分为八部分:C# 和.NET 平台、C# 核心编程结构、C# 面向对象编程、高级C# 编程...  立即去当当网订购

现在我们来深入探讨CIL代码、类型元数据和程序集清单。CIL是一种和平台无关的语言。例如,下列的C#代码构成一个简单的计算器。现在不必在意具体的语法,只要注意Calc类中的Add()方法的
格式:
// Calc.cs
using System;

namespace CalculatorExample
{
  // 这个类包含应用程序的入口点
  class Program
  {
    static void Main()
    {
      Calc c = new Calc();
      int ans = c.Add(10, 84);
      Console.WriteLine("10 + 84 is {0}.", ans);

      // 等待用户按Enter键来结束程序
      Console.ReadLine();
    }
  }

  // C#计算器
  class Calc
  {
    public int Add(int x, int y)
    { return x + y; }
  }
}

C#编译器(csc.exe)编译这段代码后,就会得到一个单文件*.exe程序集,其中包含一个程序集清单、CIL指令和描述Calc与Program类的各方面信息的元数据。

说明 第2章讲述了使用C#编译器编译代码的细节和图形IDE的使用,如Microsoft Visual Studio。

例如,如果用ildasm.exe(本章稍后会说明)打开该程序集,会发现Add()方法被CIL表示为:
.method public hidebysig instance int32 Add(int32 x,
  int32 y) cil managed
{
  //代码长度 9(0x9)
  .maxstack  2
  .locals init (int32 V_0)
  IL_0000:  nop
  IL_0001:  ldarg.1
  IL_0002:  ldarg.2
  IL_0003:  add
  IL_0004:  stloc.0
  IL_0005:  br.s IL_0007
  IL_0007:  ldloc.0
  IL_0008:  ret
} // Calc::Add方法结束

如果看不懂这段CIL代码,也不必担心,第17章会讲述CIL编程语言的基础。需要注意一点,C#编译器生成的是CIL,并不是平台相关的指令。

这一点适用于所有支持.NET的编译器。为了便于说明,我们假设用VB创建一个和上面C#相同的程序:
' Calc.vb
Imports System

Namespace CalculatorExample

  ' VB“模块”是一个只包含静态成员的类
  Module Program
    Sub Main()
      Dim c As New Calc
      Dim ans As Integer = c.Add(10, 84)
      Console.WriteLine("10 + 84 is {0}.", ans)
      Console.ReadLine()
    End Sub
  End Module

  Class Calc
    Public Function Add(ByVal x As Integer, ByVal y As Integer) As Integer
      Return x + y
    End Function
  End Class

End Namespace

如果查看Add()方法的CIL指令,你会觉得它与VB编译器vbc.exe生成的代码非常相似(只有很少的差别):
.method public instance int32 Add(int32 x,
  int32 y) cil managed
{
  //代码长度 8(0x8)
  .maxstack  2
  .locals init (int32 V_0)
  IL_0000:  ldarg.1
  IL_0001:  ldarg.2
  IL_0002:  add.ovf
  IL_0003:  stloc.0
  IL_0004:  br.s IL_0006
  IL_0006:  ldloc.0
  IL_0007:  ret
} // Calc::Add方法结束

源代码 Calc.cs和Calc.vb代码文件位于Chapter 1子目录下。

1. CIL的好处

到此,你可能很想弄清楚,不直接把源代码编译为特定的指令集而是编译为CIL的好处到底在哪里。有一点好处就是语言的集成性。如前所述,每种支持.NET的编译器生成的是几乎完全相同的CIL指令。因此,所有语言都能很好地在定义明确的二进制文件间交互。

此外,CIL是平台无关的,.NET Framework本身也是平台无关的。Java程序员早已体会到了这一点好处(例如,一个代码库就可以在多种操作系统上运行)。实际上,已经存在C#语言的国际标准和大量的.NET平台和实现的子集,它们可以供许多非Windows的操作系统使用(本章最后会详细说明)。

2. 将CIL编译成特定平台的指令

由于程序集包含的是CIL指令而不是某一特定平台的指令,CIL代码必须在使用之前进行即时编译。将CIL代码编译成有意义的CPU指令的工具称为JIT(即时)编译器,有时也称为Jitter。.NET运行库环境将使用针对各种不同CPU的JIT编译器,每个编译器都会针对底层平台进行优化。

比如,在手持设备(如Windows移动设备)上部署一个.NET应用程序,就可以配备相应的Jitter以在低内存环境下运行。另一方面,如果为后台服务器部署程序集(通常内存不是问题),那么Jitter又能进行优化,使代码在高内存环境下运行。这样,开发人员只需编写一套代码,就能在不同体系结构的设备上通过JIT编译器高效地编译和执行。

另外,当给定的Jitter编译器将CIL指令编译为相应的机器代码时,它会用适合目标操作系统的方式将结果缓存在内存中。这样,如果PrintDocument()方法被调用,则它对应的CIL指令将在第一次调用中被编译成特定平台的指令并被保留在内存中以备以后使用。因此,在下一次调用PrintDocument()时,就不需要编译CIL了。

说明 同样可以使用.NET 4.5 Framework SDK附带的ngen.exe命令行工具在安装程序时执行“预JIT”。这样做可以改善图形密集的应用程序的启动时间。

您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:1.4 .NET程序集概览
下一篇:1.4.2 .NET类型元数据的作用
相关文章
图文推荐
排行
热门
最新书评
特别推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站