这个IL指令中-2的含义是什么?

时间:2014-11-07 13:07:32

标签: c# cil il intermediate-language

我发现了一个简单程序的IL code

long x = 0;
for(long i = 0;i< int.MaxValue * 2L; i++)
{
    x = i;
}

Console.WriteLine(x);

我以发布模式构建此代码,并生成此IL code

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       28 (0x1c)
  .maxstack  2
  .locals init ([0] int64 x,
           [1] int64 i)
  IL_0000:  ldc.i4.0
  IL_0001:  conv.i8
  IL_0002:  stloc.0
  IL_0003:  ldc.i4.0
  IL_0004:  conv.i8
  IL_0005:  stloc.1
  IL_0006:  br.s       IL_000f
  IL_0008:  ldloc.1
  IL_0009:  stloc.0
  IL_000a:  ldloc.1
  IL_000b:  ldc.i4.1
  IL_000c:  conv.i8
  IL_000d:  add
  IL_000e:  stloc.1
  IL_000f:  ldloc.1
  IL_0010:  ldc.i4.s   -2
  IL_0012:  conv.u8
  IL_0013:  blt.s      IL_0008
  IL_0015:  ldloc.0
  IL_0016:  call       void [mscorlib]System.Console::WriteLine(int64)
  IL_001b:  ret
} // end of method Program::Main

除了这个以外,我几乎找出了所有的解释:

 IL_0010:  ldc.i4.s   -2

现在这个insruction应该将int.MaxValue * 2L推到堆栈上,然后blt.s会将其与i进行比较,如果i小于值,则返回IL_0008 1}}。但是,我无法弄清楚它为什么会加载 -2 ?如果我改变循环如下:

for(long i = 0;i < int.MaxValue * 3L; i++)
{
     x = i;
}

加载预期值:

IL_0010:  ldc.i8     0x17ffffffd

那么这段代码中-2的含义是什么?

2 个答案:

答案 0 :(得分:13)

int.MaxValue * 2L是一个64位数字,但仍适用于32位(4,294,967,2940xFFFFFFFE)。因此,编译器正在加载0xFFFFFFFE(当解释为Int32时等于-2),然后将其扩展为无符号的64位值。

它使用签名表单的原因是,当被解释为带符号的值-2时,该数字适合单个带符号的字节(-128127),这意味着编译器能够发出短格式ldc.i4.s操作码以从单个字节加载32位值。它只需要2个字节来加载32位有符号整数,另外1个字节用于将其转换为64位值 - 这比使用64位加载指令后跟一个完整的8字节无符号整数要好得多。 / p>

答案 1 :(得分:3)

看起来编译器正在使用按位数学。恰好是Two's Complement值-2等于(int.MaxValue * 2L)的无符号整数值

以按位表示:

-                                          1111 1111 1111 1111 1111 1111 1111 1110 (int)
-                                          1111 1111 1111 1111 1111 1111 1111 1110 (uint)
-  0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 1111 1111 1111 1111 1111 1110 (long