2017-06-24 7 views
2

小さなコードスニペットを書き、コンパイルされたアセンブリを調べることによってCILを学ぼうとしています。ILコードにstloc.0の直後にldloc.0があるのはなぜですか?

.method public hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    .maxstack 2 
    .locals init (
     [0] int32 num, 
     [1] bool flag) 
    L_0000: nop 
    L_0001: call string [mscorlib]System.Console::ReadLine() 
    L_0006: call int32 [mscorlib]System.Int32::Parse(string) 
    L_000b: stloc.0 
    L_000c: ldloc.0 
    L_000d: ldc.i4.0 
    L_000e: cgt 
    L_0010: ldc.i4.0 
    L_0011: ceq 
    L_0013: stloc.1 
    L_0014: ldloc.1 
    L_0015: brtrue.s L_0022 
    L_0017: ldstr "i is greater than 0" 
    L_001c: call void [mscorlib]System.Console::WriteLine(string) 
    L_0021: nop 
    L_0022: ret 
} 

私が知っているように、stlocはローカル変数に評価スタックから一番上の値を置く:以下ILコードにそれをコンパイル

public static void Main (string[] args) 
    { 
     Int32 i = Int32.Parse (Console.ReadLine()); 
     if (i > 0) 
      Console.WriteLine ("i is greater than 0"); 
    } 

そして、C#コンパイラ:だから私はこの単純なif文を書きました私が正しいとすれば、その値はスタックからポップされないので、コンパイラはなぜそれの直後にldloc命令を置くのでしょうか?

+5

いいえ、stloc *はスタックをポップします。 ldlocが非常に非効率に見えるかもしれませんが、.NETコンパイラの出力は最適化されていません。そのように動作することが重要である場合は、コードをデバッグするのにかなりの時間を要します。リリースビルドのJITコンパイラによって、後で最適化されます。マシンコードの最適化であり、CILの最適化ではありません。 stloc/ldlocに相当するものは表示されません。変数はCPUレジスタに格納されます。 –

+0

@ HansPassantしかし、.netコンパイラは最適化を行います(デフォルトで) 'string s =" abc "; Console.WriteLine(s);'のようなものをコンパイルし、出力されたILをチェックします。 – IDavid

+0

@ IDavid - 定数フォールディングなど、最適化フラグがオンになっていなくてもC#コンパイラが実行する最適化がいくつかあります。しかし、最適化をオフにしたあなたの例では、LINQPadの "abc"リテラルのstloc.0 ldloc.0シーケンスを実際に取得します。最適化の設定については、こちらを参照してください。https://blogs.msdn.microsoft.com/ericlippert/2009/06/11/what-does-the-optimize-switch-do/ – hoodaticus

答えて

3

デバッグモードでのみ表示されるのは、コンパイラがコードを最適化しないためです。デバッグして特定の部分にブレークポイントを入れることができます。

リリースモードでこのアプリケーションをコンパイルすると、ILコードであっても最適化が行われていることがわかります。

.method public hidebysig static void 
    Main(
    string[] args 
) cil managed 
{ 
    .entrypoint 
    .maxstack 8 

    // [13 13 - 13 55] 
    IL_0000: call   string [mscorlib]System.Console::ReadLine() 
    IL_0005: call   int32 [mscorlib]System.Int32::Parse(string) 

    // [14 13 - 14 23] 
    IL_000a: ldc.i4.0  
    IL_000b: ble.s  IL_0017 

    // [15 17 - 15 58] 
    IL_000d: ldstr  "i is greater than 0" 
    IL_0012: call   void [mscorlib]System.Console::WriteLine(string) 

    // [16 9 - 16 10] 
    IL_0017: ret   

} // end of method Program::Main 
+0

ありがとう、今私は理解しています。 – IDavid

関連する問題