小さなコードスニペットを書き、コンパイルされたアセンブリを調べることによって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
命令を置くのでしょうか?
いいえ、stloc *はスタックをポップします。 ldlocが非常に非効率に見えるかもしれませんが、.NETコンパイラの出力は最適化されていません。そのように動作することが重要である場合は、コードをデバッグするのにかなりの時間を要します。リリースビルドのJITコンパイラによって、後で最適化されます。マシンコードの最適化であり、CILの最適化ではありません。 stloc/ldlocに相当するものは表示されません。変数はCPUレジスタに格納されます。 –
@ HansPassantしかし、.netコンパイラは最適化を行います(デフォルトで) 'string s =" abc "; Console.WriteLine(s);'のようなものをコンパイルし、出力されたILをチェックします。 – IDavid
@ IDavid - 定数フォールディングなど、最適化フラグがオンになっていなくてもC#コンパイラが実行する最適化がいくつかあります。しかし、最適化をオフにしたあなたの例では、LINQPadの "abc"リテラルのstloc.0 ldloc.0シーケンスを実際に取得します。最適化の設定については、こちらを参照してください。https://blogs.msdn.microsoft.com/ericlippert/2009/06/11/what-does-the-optimize-switch-do/ – hoodaticus