【发布时间】:2010-04-09 12:27:51
【问题描述】:
我正在尝试了解 while 循环在 IL 中的外观。我已经编写了这个 C# 函数:
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 吗?
【问题讨论】:
-
一个额外的金块给你,基于“因为它不重要”和你的推特提要......注意
br*_s和br*之间的区别。_s变体使用较小的 相对 偏移量,如果位置不靠近,将不起作用(非_s变体使用 absolute 没有“小”限制的偏移量)。因此,如果您的编译器无法(提前)预测正文的大小,请使用br*而不是br*_s。 -
@Marc 谢谢,正好遇到了这个问题:D 我的演示应用程序只有一条指令,因此编译器生成了 _s 变体,但我真正的编译器有更长的循环体。积极的副作用:我从那个“非法的单字节分支”异常中学到了一些东西:)
-
IIRC,如果您使用正确的方法,ILGenerator 足够聪明,可以针对当前情况发出正确的操作码。
-
@Nick - 来自(最近的)记忆我不这么认为。不过,我可能是错的。