ホームページ  >  記事  >  バックエンド開発  >  C# の CLR (共通言語ランタイム) と IL (中間コード)

C# の CLR (共通言語ランタイム) と IL (中間コード)

黄舟
黄舟オリジナル
2017-02-07 15:44:011865ブラウズ

.net プラットフォームの CLR

まず説明することは、.NET プラットフォームは C# と同じものではなく、C# や VB.net などのプログラムが実行されるプラットフォームです。

CLR は共通言語ランタイムであり、.NET Framework の重要な部分です。メモリ管理、スレッド管理、例外処理などのサービスを提供し、コードの正確性を保証するためにコードに厳密な型安全性チェックを実装する責任もあります。

実際、タイプ セーフティ (型チェッカー)、ガベージ コレクション (ガベージ コレクター)、例外処理 (例外マネージャー)、下位互換性 (COM マーシャラー) などの C# の多くの機能が CLR によって提供されます。

IL とは

.NET Framework は、Windows プラットフォーム上に構築された仮想実行プラットフォームです。Windows を Linux などの他のオペレーティング システムに置き換えることも想像できますが、CLS (共通言語仕様、共通言語) を引き続き使用できます。仕様) .NET 言語、これは実際に Mono が実現しようとしている機能です。したがって、理論上、C# はクロスプラットフォーム言語です。

C# が Java に似ているもう 1 つの点は、C# が (特別な意味で) 言語でもあることです。C# で書かれたプログラム コードは、最初に C# コンパイラー (Microsoft 中間言語) によって特殊なバイト コードにコンパイルされます。 、MSIL、Microsoft)中間言語。オペレーティング システムによる実行のために、実行時に特定のコンパイラ(JIT コンパイラ、Just In tIME、JITer)によってマシン コードにコンパイルされます。

IL は中間言語です。.NET プラットフォーム上のさまざまな高級言語 (C#、VB、F# など) のコンパイラーは、それぞれのテキスト式を IL に変換します。さまざまなテキスト形式が最終的に IL の表現に統一されました

CLR が IL をロードした後、各メソッドが初めて実行されるときに、JIT を使用して IL コードを機械語コード、機械語コード、アセンブリにコンパイルします。 1 対 1 の対応関係。これは次のように理解できます。アセンブリは機械語コードのテキスト表現であり、人々が覚えておくと便利な「ニーモニック」を提供します。

同じ IL の場合、JIT は異なる CPU アーキテクチャ (x86/IA64 など) に応じて異なるマシン コードを生成します。

C# コードとそれに対応する IL 中間コード

C# の CLR (共通言語ランタイム) と 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: コード内の変数は、呼び出しスタック (呼び出しスタック) 内のいくつかの位置を占める必要があります。 (...): 変数の初期化を定義し、呼び出しスタックに入れます (呼び出しスタック); nop: 操作なし、操作なし; ldstr: 文字列をロードし、文字列を評価スタックにプッシュします


ldc.i4.1: 値 2 を 4 バイト長の整数の形式で評価スタックにプッシュします。 stloc: 値を評価スタック (評価) にポップし、それを呼び出しスタック (呼び出しスタック) に割り当てます。 ldloc: 呼び出しを実行します。呼び出しスタック内の指定された位置にある値が取り出され (コピー)、評価スタックにプッシュされます。 call: 指定されたメソッドを呼び出します。この命令は通常、静的メソッドを呼び出すために使用されます。インスタンスメソッドを呼び出す 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
}

上記はC#のCLR(共通言語ランタイム)とIL(中間コード)の内容です。その他の関連コンテンツPHPに注意してください。中国語のウェブサイト (www.php.cn)!


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。