我发现了一个简单程序的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
的含义是什么?
答案 0 :(得分:13)
int.MaxValue * 2L
是一个64位数字,但仍适用于32位(4,294,967,294
或0xFFFFFFFE
)。因此,编译器正在加载0xFFFFFFFE
(当解释为Int32
时等于-2),然后将其扩展为无符号的64位值。
它使用签名表单的原因是,当被解释为带符号的值-2
时,该数字适合单个带符号的字节(-128
到127
),这意味着编译器能够发出短格式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