在已编译的C#程序中使用ILDASM.exe时,它显示方法中的每条指令都有一个标签。
例如:
IL_0001: ldc.i4.4
IL_0002: stloc.0
IL_0003: ldc.r8 12.34
IL_000c: stloc.1
IL_000d: ldc.r8 3.1415926535897931
IL_0016: stloc.2
IL_0017: ldstr "Ehsan"
IL_001c: stloc.3
IL_001d: ret
这是为什么?这样做效率不高或者CIL编译器本身是否优化这些标签?
答案 0 :(得分:9)
已编译的CIL中不存在标签。它们是为了方便您在反汇编代码中显示的。
这些特殊标签对应于指令偏移,而手工制作的代码没有这样的限制(标签可以是任意字符串)。
答案 1 :(得分:5)
在编译的IL中,没有标签。相反,跳转指令使用从下一条指令开始的相对偏移量。
例如,考虑一下这个简单的C#函数:
public static bool IsZero(int n)
{
if (n == 0)
return true;
return false;
}
在IL中,您可以这样写:
.method public hidebysig static bool IsZero(int32 n) cil managed
{
ldarg.0
brtrue.s label
ldc.i4.1
ret
label:
ldc.i4.0
ret
}
如果使用ilasm编译它,然后使用ildasm将其反编译,使用"显示字节"启用后,您将获得:
.method public hidebysig static bool IsZero(int32 n) cil managed
// SIG: 00 01 02 08
{
// Method begins at RVA 0x2052
// Code size 7 (0x7)
.maxstack 8
IL_0000: /* 02 | */ ldarg.0
IL_0001: /* 2D | 02 */ brtrue.s IL_0005
IL_0003: /* 17 | */ ldc.i4.1
IL_0004: /* 2A | */ ret
IL_0005: /* 16 | */ ldc.i4.0
IL_0006: /* 2A | */ ret
} // end of method Program::IsZero
注意标签不以任何方式表示在字节中(显示在注释中)。原始IL中的brtrue.s label
在此处显示为brtrue.s IL_0005
,其中字节为2D 02
。 2D
是brtrue.s
的编译形式,02
是相对偏移量。由于以下指令以绝对偏移3开始,因此目标处于绝对偏移3 + 2 = 5。