Heim >Backend-Entwicklung >C#.Net-Tutorial >CLR (Common Language Runtime) und IL (Intermediate Code) in C#
CLR in der .net-Plattform
Zunächst ist zu beachten, dass die .NET-Plattform nicht dasselbe ist wie C#. Es ist die Plattform, auf der Programme wie C# und VB.net laufen .
CLR ist die Common Language Runtime und ein wichtiger Bestandteil des .NET Frameworks. Es bietet Dienste wie Speicherverwaltung, Thread-Verwaltung und Ausnahmebehandlung und ist außerdem für die Implementierung strenger Typsicherheitsprüfungen des Codes verantwortlich, um die Korrektheit des Codes sicherzustellen.
Tatsächlich werden viele Funktionen in C# wie Typsicherheit (Type Checker), Garbage Collection (Garbage Collector), Ausnahmebehandlung (Exception Manager), Abwärtskompatibilität (COM Marshaler) usw. von der CLR bereitgestellt .
Was ist IL
.NET Framework ist eine virtuelle Laufplattform, die auf der Windows-Plattform basiert. Sie können sich vorstellen, die unterste Ebene von Windows durch andere Betriebssysteme wie Linux zu ersetzen Es ist möglich, eine .NET-Sprache zu verwenden, die CLS (Common Language Specification, Common Language Specification) entspricht. Dies ist tatsächlich die Funktion, die Mono erreichen möchte. Daher ist C# theoretisch eine plattformübergreifende Sprache.
Eine weitere Sache, die C# eher zu Java macht, ist, dass es auch eine Sprache ist (in einem besonderen Sinne wird der in C# geschriebene Programmcode zunächst vom C#-Compiler in ein Sonderzeichen kompiliert). Code, (Microsoft Intermediate Language, MSIL, Microsoft) Zwischensprache, wird von einem bestimmten Compiler (JIT-Compiler, Just In tIME, JITer) zur Laufzeit zur Ausführung durch das Betriebssystem in Maschinencode kompiliert.
IL ist eine Zwischensprache. Die Compiler verschiedener Hochsprachen (wie C#, VB, F#) auf der .NET-Plattform konvertieren ihre jeweiligen Textausdrücke in IL. Verschiedene Textformen wurden schließlich im IL-Ausdruck vereinheitlicht
Nachdem CLR IL geladen hat, wird JIT verwendet, um den IL-Code in Maschinencode zu kompilieren und tatsächlich zu assemblieren Es gibt eine Eins-zu-eins-Entsprechung. Dies kann folgendermaßen verstanden werden: Assembly ist die Textdarstellung von Maschinencode und bietet einige „Mnemoniken“, die sich die Leute leicht merken können.
Für dieselbe IL generiert JIT unterschiedliche Maschinencodes für unterschiedliche CPU-Architekturen (z. B. x86/IA64 usw.).
C#-Code und der entsprechende IL-Zwischencode
//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方法结束
Durch den obigen Code können wir Folgendes zusammenfassen: .maxstack: Variablen im Code, die es benötigt um mehrere Positionen im Aufrufstapel zu belegen (Call Stack); .locals int(...): Variableninitialisierung definieren und in den Aufrufstapel einfügen (Call Stack); Schieben Sie die Zeichenfolge in den Auswertungsstapel.
ldc.i4.1: Schieben Sie den Wert 2 in Form einer 4-Byte-Ganzzahl in den Auswertungsstapel. Legen Sie den Wert im Auswertungsstapel (Evaluation) ab und weisen Sie ihn dem Aufrufstapel (Call Stack) zu. ldloc: Nehmen Sie den Wert an der angegebenen Position im Aufrufstapel (Call Stack) heraus (kopieren Sie ihn) und verschieben Sie ihn in den Auswertungsstapel (Auswertungsstapel); Aufruf: Diese Anweisung wird im Allgemeinen zum Aufrufen statischer Methoden verwendet. Callvir wird im Allgemeinen zum Aufrufen von Instanzmethoden verwendet.
Sehen wir uns ein weiteres Beispiel an
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(); } } }
Der entsprechende IL-Code der Hauptmethode:
.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 }
Das Obige ist die CLR (Common Language) in C# Laufzeit) und IL-Inhalte (Zwischencode). Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn).