首先要申明的是,.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(中心代码)的内容,更多相关内容请关注ki4网(www.ki4.cn)!