2015-12-07 6 views
3

При использовании ILDASM.exe в скомпилированной программе на C#, это показывает, что для каждой инструкции в методах есть метка.Почему у C# -> CIL есть метка на каждой инструкции?

Например:

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 оптимизирует эти метки самостоятельно?

+3

Что заставляет вас думать, что это ярлык, а не только как ildasm отображает IL? –

+0

, так что это похоже на строку «IL_0001»? @JonSkeet –

+1

@EhsanSajjad: Вид. Я считаю, что они действуют как ярлыки, которые вы * можете использовать в IL, но я не верю, что они находятся в фактическом сгенерированном коде. –

ответ

9

Этикетки нет в скомпилированном CIL. Они отображаются для вашего удобства в разобранном коде.

Эти конкретные ярлыки соответствуют смещениям инструкций, в то время как таких ограничений нет в рукописном коде (метки могут быть произвольными строками).

+2

Возможно, проще просто обеспечить, чтобы каждая инструкция давала ярлык, а не отслеживать, какие метки должны испускаться, и только излучать их. –

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 

Обратите внимание, что эти метки не находятся в любым способом, представленным в байтах (показано в комментариях). И что brtrue.s label от оригинального IL здесь изображается как brtrue.s IL_0005, где байты 2D 02. 2D - скомпилированная форма brtrue.s, а 02 - относительное смещение. Так как следующая инструкция начинается с абсолютного смещения 3, цель находится на абсолютном смещении 3 + 2 = 5.