您好,欢迎访问一九零五行业门户网

C#中CLR(公共语言运行时)与IL(中间代码)

.net平台中的clr
首先要说明的是,.net平台与c#不是一回事 它是c#,vb.net等程序运行的平台。
clr是公共语言运行时,是 .net framework的重要组成部分。它提供了内存管理、线程管理和异常处理等服务,而且还负责对代码实施严格的类型安全检查,保证了代码的正确性。
事实上,类型安全(type checker)、垃圾回收(garbage collector)、异常处理(exception manager)、向下兼容(com marshaler)等很多c#中的特性都是由clr来提供的。
什么是il
.net framework是架构在windows平台上的一个虚拟的运行平台,你可以想象将最下层windows换做其他的操作系统,例如说linux,一样可以实现使用符合cls(common language specification,通用语言规范)的.net语言,这其实就是mono计划要实现的功能。因而,理论上,c#是一种可以跨平台的语言。
c#另一个比较象java的地方是,它也是一种(特殊意义上的)语言,同java一样,c#编写的程序代码也是先通过c#编译器编译为一种特殊的字节代码, (microsoft intermediate language,msil,微软)中间语言,运行时再经由特定的编译器(jit编译器,just in time, jiter)编译为机器代码,以供操作系统执行。
il是一门中间语言 ,.net平台上的各种高级语言(如c#,vb,f#)的编译器会将各自的文字表述方式转化为il。各种不同的文字形式最终被统一到了il的表述方式
clr加载了il之后,当每个方法第一次被执行时,就会使用jit将il代码进行编译为机器码,机器码和汇编其实也是一一对应的,可以这样理解:汇编是机器码的文字表现形式,提供了一些方便人们记忆的“助记符”。
对于同样的il,jit会把它为不同的cpu架构(如x86/ia64等等)生成不同的机器码。
c#代码及其对应的il中间代码
//hidebysig指令表示如果当前类为父类,用该指令标记的方法将不会被子类继承 //cil managed表明方法体中的代码是il代码,且是托管代码,即运行在clr运行库上的代码 .method private hidebysig static void main(string[] args)cil managed { .entrypoint //该指令代表该函数程序的入口函数。每一个托管应用程序都有且只有一个入口函数,clr加载程序时,首先从.entrypoint函数开始执行。 .maxstack 2 //执行构造函数时,评估堆栈可容纳数据项的最大个数。评估堆栈是保存方法中所需要变量的值的一个内存区域,该区域在方法执行结束时会被清空, 或者存储一个返回值。 .locals init ( [0] int32 num, [1] int32 num2, [2] int32 num3) //表示定义int类型的变量,变量名分别为num,num2,num3。存储在调用栈。 l_0000: nop //no operation的意思,即没有任何操作。 l_0001: ldc.i4.1 //将“1”压入评估栈,此时“1”处于评估栈的栈顶。 l_0002: stloc.0 //此指令表示把值从评估栈中弹出,并赋值给调用栈的第0个变量num。 l_0003: ldc.i4.2 l_0004: stloc.1 l_0005: ldc.i4.3 l_0006: stloc.2 //从.locals init到l_0006,相当于c#代码的为i,j,k赋值。 l_0007: ldloc.0 //取调用栈中位置为0的元素压入评估栈(取i的值)。 l_0008: ldloc.1 //取调用栈中位置为1的元素压入评估栈(取j的值)。 l_0009: add //做加法操作 l_000a: ldloc.2 //取调用栈中位置为2的元素压入评估栈(取k的值)。 l_000b: add //做加法操作 l_000c: call void [mscorlib]system.console::writeline(int32) //调用输出方法 l_0011: nop //no operation l_0012: call valuetype [mscorlib]system.consolekeyinfo [mscorlib]system.console::readkey() //调用readkey方法 l_0017: pop //把评估栈的内容清空 l_0018: ret //return 标记返回值 } //main方法结束
通过上面的代码,我们可以总结一下: .maxstack:代码中变量需要在调用栈(call stack)中占用几个位置; .locals int(……):定义变量初始化并放入调用栈中(call stack); nop:no operation,没有任何操作; ldstr:load string,把字符串压入评估栈(evaluation stack)中;
ldc.i4.1:把数值2以4字节长度整数的形式压入评估栈; stloc:把评估栈(evaluation)中的值弹出赋值到调用栈中(call stack); ldloc:把调用栈(call stack)中指定位置的值取出(copy)压入评估栈(evaluation stack)中; call:调用指定的方法,这个指令一般用于调用静态方法;而callvir则一般用于调用实例方法; ret:return ,标记返回。
下面再看一个例子
namespace testconsole { class program { [methodimpl(methodimploptions.noinlining)] private static void somemethod() { console.writeline("hello world!"); } static void main(string[] args) { console.writeline("before jited."); console.readline(); somemethod(); console.writeline("after jited"); console.readline(); } } }
与之相对应的main方法il代码:
.method private hidebysig static void main(string[] args) cil managed { .entrypoint .maxstack 8 // 分配字符串"before jited" l_0000: ldstr "before jited." // 调用console.writeline方法 l_0005: call void [mscorlib]system.console::writeline(string) // 调用console.readline方法 l_000a: call string [mscorlib]system.console::readline() l_000f: pop // 调用program.somemethod方法 l_0010: call void testconsole.program::somemethod() // 分配字符串"after jited" l_0015: ldstr "after jited" // 调用console.writeline方法 l_001a: call void [mscorlib]system.console::writeline(string) // 调用console.readline方法 l_001f: call string [mscorlib]system.console::readline() l_0024: pop l_0025: ret }
以上就是c#中clr(公共语言运行时)与il(中间代码)的内容。
其它类似信息

推荐信息