2013-10-06 10 views
12

Così ho scritto il seguente codice in C#.Qual è il punto di nop in CIL

class Test 
{ 
    int a; 
    System.IO.StreamReader reader; 

    public Test() 
    { 
     a = 5; 
     reader = new System.IO.StreamReader(String.Empty); 
    } 
} 

E il costruttore della classe in IL assomiglia a questo

.method public hidebysig specialname rtspecialname 
     instance void .ctor() cil managed 
{ 
    // Code size  33 (0x21) 
    .maxstack 8 
    IL_0000: ldarg.0 
    IL_0001: call  instance void [mscorlib]System.Object::.ctor() 
    IL_0006: nop 
    IL_0007: nop 
    IL_0008: ldarg.0 
    IL_0009: ldc.i4.5 
    IL_000a: stfld  int32 Test2.Test::a 
    IL_000f: ldarg.0 
    IL_0010: ldsfld  string [mscorlib]System.String::Empty 
    IL_0015: newobj  instance void [mscorlib]System.IO.StreamReader::.ctor(string) 
    IL_001a: stfld  class [mscorlib]System.IO.StreamReader Test2.Test::reader 
    IL_001f: nop 
    IL_0020: ret 
} // end of method Test::.ctor 

Ci sono 3 nop comandi. (Che come so non significa nessuna operazione). Qual è la necessità di quei comandi. Voglio dire quale sarebbe la differenza se non ci fosse alcun comando invece di nop

risposta

16

Vengono utilizzati dal compilatore C# quando scrive il file .pdb per il programma. Che contiene informazioni di debug, che includono le informazioni sul numero di riga + del file per il tuo codice. Il debugger usa questo per trovare il codice macchina dove è necessario iniettare un'istruzione INT 3 per arrestare l'esecuzione del programma quando si imposta un punto di interruzione. Il jitter emette un'istruzione NOP per codice macchina per ogni Opcodes. Nulla in MSIL.

Il primo nop viene utilizzato quando si imposta un punto di interruzione su public Test(). Si noti che è stato iniettato dopo la chiamata del costruttore di base in modo che la variabile questa diventi valida nelle finestre di debug di Auto/Locals/Watch.

Il secondo nop viene utilizzato quando si imposta un punto di interruzione sul primo {parentesi graffa. Quella linea non genera alcun codice quindi c'è un forte bisogno di un'istruzione MSIL falsa.

Stessa storia per il terzo nop, generato per l'ultimo} parentesi graffa. Quando si imposta un punto di interruzione su quello, è possibile esaminare il valore di ritorno del metodo (se presente). Visibile indirettamente nella finestra Debug + Windows + Registers. Migliorato in VS2013.

Quindi questo aiuta solo a eseguire il debug del programma, in modo che i punti di interruzione funzionino in modo prevedibile. Questi NOP sono non generati quando si crea la configurazione di rilascio del programma. Uno dei motivi principali per cui un progetto C# ha una configurazione di debug e release. Puoi ancora eseguire il debug di una build di rilascio, è comunque un'esperienza piuttosto confusa che ti fa dubitare della tua sanità mentale :)

3

Sono usati per supportare i breakpoint quando si costruisce in modalità debug e non farà alcuna differenza nell'esecuzione dell'assembly.