为什么C# – > CIL在每条指令上都有标签?

在已编译的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编译器本身是否优化这些标签?

编译的CIL中不存在标签。 它们是为了方便您在反汇编代码中显示的。

这些特定标签对应于指令偏移,而手工代码没有这样的限制(标签可以是任意字符串)。

在编译的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 022Dbrtrue.s的编译forms, 02是相对偏移量。 由于以下指令以绝对偏移3开始,因此目标处于绝对偏移3 + 2 = 5。