我想了解IL在while循环中的外观。我写了这个C#函数:IL中的循环 - 为什么stloc.0和ldloc.0?
static void Brackets()
{
while (memory[pointer] > 0)
{
// Snipped body of the while loop, as it's not important
}
}
的IL看起来是这样的:
.method private hidebysig static void Brackets() cil managed
{
// Code size 37 (0x25)
.maxstack 2
.locals init ([0] bool CS$4$0000)
IL_0000: nop
IL_0001: br.s IL_0012
IL_0003: nop
// Snipped body of the while loop, as it's not important
IL_0011: nop
IL_0012: ldsfld uint8[] BFHelloWorldCSharp.Program::memory
IL_0017: ldsfld int16 BFHelloWorldCSharp.Program::pointer
IL_001c: ldelem.u1
IL_001d: ldc.i4.0
IL_001e: cgt
IL_0020: stloc.0
IL_0021: ldloc.0
IL_0022: brtrue.s IL_0003
IL_0024: ret
} // end of method Program::Brackets
在大多数情况下,这是非常简单的,除了CGT之后的部分。
我不明白的是本地[0]和stloc.0/ldloc.0。就我所见,cgt将结果推送到堆栈,stloc.0从堆栈中获取结果到本地变量中,ldloc.0再次将结果推送到堆栈,并且brtrue.s从堆栈中读取。
这样做的目的是什么?难道这不能简化为cgt跟brtrue.s?
基于“因为它不重要”和你的twitter饲料,你会得到额外的金块......注意'br * _s'和'br *'之间的区别。 '_s'变体使用一个小的*相对*偏移量,如果位置不靠近,**将不起作用(非's'变体使用*绝对*偏移量而没有“小”限制)。因此,如果你的编译器不能预测(预先)body的大小,那么使用'br *'优先于'br * _s'。 – 2010-04-09 05:05:31
@Marc谢谢,碰到这个问题:D我的Demo应用程序有一条指令,所以编译器生成_s变体,但是我真正的编译器有更长的循环体。积极的副作用:我从那个“非法的单字节分支”例外中学到了一些东西:) – 2010-04-09 05:15:23
IIRC,ILGenerator足够聪明,可以为手边的情况发出正确的操作码,如果您使用正确的方法。 – 2010-04-09 07:41:44