집 >백엔드 개발 >C#.Net 튜토리얼 >C#의 CLR(공용 언어 런타임) 및 IL(중간 코드)
.net 플랫폼의 CLR
우선 .NET 플랫폼은 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 Spec, 공통 언어 사양)를 준수하는 .NET 언어를 사용하는 것이 가능합니다. 이것이 실제로 Mono가 달성하려는 기능입니다. 따라서 이론적으로 C#은 크로스 플랫폼 언어입니다.
C#을 Java와 더 비슷하게 만드는 또 다른 점은 C#도 (특별한 의미에서) 언어라는 점입니다. Java와 마찬가지로 C#으로 작성된 프로그램 코드는 먼저 C# 컴파일러 섹션에 의해 특수 문자로 컴파일됩니다. 코드(Microsoft Intermediate Language, MSIL, Microsoft) 중간 언어는 운영 체제에서 실행하기 위해 런타임에 특정 컴파일러(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: 코드의 변수는 다음과 같아야 합니다. in 호출 스택(콜 스택)에서 여러 위치를 차지합니다. .locals int(...): 변수 초기화를 정의하고 호출 스택에 넣습니다(콜 스택). nop: 작업 없음, 작업 없음; 문자열을 평가 스택에 푸시합니다.
ldc.i4.1: 값 2를 4바이트 길이의 형식으로 평가 스택에 푸시합니다. 정수; stloc: 평가 스택(Evaluation)에서 값을 팝하고 이를 호출 스택(Call Stack)에 할당합니다. ldloc: 호출 스택(Call Stack)의 지정된 위치에 있는 값을 꺼내(복사)하고 푸시합니다. 평가 스택(평가 스택)에 호출: 지정된 메서드를 호출합니다. 이 명령은 일반적으로 정적 메서드를 호출하는 데 사용됩니다. ret: return, mark 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(); } } }
해당 기본 메소드 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 }
위는 CLR(공용 언어 런타임) 및 IL(중간 코드)입니다. ) 콘텐츠, 더 많은 관련 콘텐츠를 보려면 PHP 중국어 웹사이트(www.php.cn)를 주목하세요!