2015-11-13 45 views
5

Così ho preso uno sguardo al ILDASM, l'ispezione di un exe che assomiglia a questo:Che cosa fa esattamente l'operatore ==?

int a = 2; 
Int32 b = 1; 
if(b == 1) 
{ 

} 

Ora, il codice CIL sembra che:

IL_0005: ldloc.1 
IL_0006: ldc.i4.1 
IL_0007: ceq 
IL_0009: ldc.i4.0 
IL_000a: ceq 
IL_000c: stloc.2 

Capisco che prima b viene caricato (che è memorizzato in [1]), quindi una costante con il valore di 1 e quindi vengono confrontati. Quello che non capisco è il motivo per cui un'altra costante con il valore 0 viene caricata e confrontata, prima che il risultato di tale confronto venga memorizzato.
Poiché il primo confronto dovrebbe già produrre un valore di verità, controllando se questo valore è 0 inverte il risultato, giusto?
La mia domanda è ora: perché è invertita? Suppongo che abbia qualcosa a che fare con l'operatore == che ho usato e la mia teoria è che restituisce la differenza. Se questa differenza è 0, i valori sono gli stessi, quindi il risultato dovrebbe essere vero. Ma 0 sta per falso, quindi deve essere invertito.
Non riesco a trovare nulla su questo argomento, solo qualcosa su operatori come == ~ o simili. Spero che mi può illuminare :)

migliori saluti

Wilsu

PS: Questo è il codice completo:

.method private hidebysig instance void Form1_Load(object sender, 
               class [mscorlib] 
System.EventArgs e) cil managed 
{ 
// Code size  19 (0x13) 

.maxstack 2 
.locals init ([0] int32 a, 
     [1] int32 b, 
     [2] bool CS$4$0000) 
IL_0000: nop 
IL_0001: ldc.i4.2 
IL_0002: stloc.0 
IL_0003: ldc.i4.1 
IL_0004: stloc.1 
IL_0005: ldloc.1 
IL_0006: ldc.i4.1 
IL_0007: ceq 
IL_0009: ldc.i4.0 
IL_000a: ceq 
IL_000c: stloc.2 
IL_000d: ldloc.2 
IL_000e: brtrue.s IL_0012 
IL_0010: nop 
IL_0011: nop 
IL_0012: ret 
} // end of method Form1::Form1_Load 
+1

Non ho affatto quell'IL. La mia ipotesi è che proviene da un altro pezzo del codice. Per favore pubblica un breve esempio * completo *. –

+0

Ottengo lo stesso risultato (almeno simile) con solo questo codice all'interno principale. – Rob

+0

stai compilando in versione? (Non vedo alcun "nop", ma ...), e: è questo il * intero * codice? Sembra che abbia fatto qualche divertente riordino, p Ma: Non vedo una terza variabile, quindi non è ovvio per me cosa 'stloc.2' even * significa * ... –

risposta

1

Sta facendo un salto alla fine della funzione, per quanto posso raccogliere.

void Main() 
{ 
    int a = 2; 
    Int32 b = 1; 
    if(b == 1) 
    { 
     Console.WriteLine("A"); 
    } 
} 

Mi dà:

IL_0000: nop   
IL_0001: ldc.i4.2  
IL_0002: stloc.0  // a 
IL_0003: ldc.i4.1  
IL_0004: stloc.1  // b 
IL_0005: ldloc.1  // b 
IL_0006: ldc.i4.1  
IL_0007: ceq   
IL_0009: ldc.i4.0  
IL_000A: ceq   
IL_000C: stloc.2  // CS$4$0000 
IL_000D: ldloc.2  // CS$4$0000 
IL_000E: brtrue.s IL_001D 
IL_0010: nop   
IL_0011: ldstr  "A" 
IL_0016: call  System.Console.WriteLine 
IL_001B: nop   
IL_001C: nop   
IL_001D: ret   

Partendo da IL_0005, abbiamo:

carico b.
Carico 1.
ceq (Se uguale, spingere 1, se falsa spinta 0) - Risultato qui sarà 1
carico 0
ceq - Risultato qui sarà 0
brtrue.s IL_001D - Se il valore è diverso da zero, passa IL_001D (fine della funzione)

Quindi è essenzialmente compilato per questo:

int a = 2; 
Int32 b = 1; 
if(!(b == 1)) 
    goto end; 
Console.WriteLine("A"); 
:end 
return; 
+2

per il contesto, quando compilo questo (ottimizzato) ottengo: 'ldc.i4.1',' ldc.i4.1', 'bne.un.s {al ret}', 'ldstr" A "', 'call void [mscorlib] System.Console :: WriteLine (stringa)', 'ret' - molto diverso –

+0

anche se francamente sono un po 'deluso dal fatto che non lo rimuove completamente e lo compili a' ret', dal confronto di due costanti a runtime sembra ... stupido –

+0

Grazie mille, questo è esattamente quello che volevo sapere. – Wilsu

3

ceq prende due valori dallo stack e produce 1 se sono considerati uguali e 0 se non lo sono. Tuttavia, se == in C# risultati in ceq dipende da un sacco di cose:

  • i tipi di dati
    • sono loro primitive?
    • hanno operatori personalizzati ==?
    • sono riferimenti?
  • contesto
    • può che essere ottimizzato per qualcos'altro? (Ho un bne.un.s in un esempio simile, c'è anche beq*, br*, switch, ecc.)
    • può essere rimosso completamente?
+0

Per quanto riguarda i tipi di dati: è per questo che ho usato gli interi. Tipi di dati primitivi, nessun operatore sovraccarico. Non mi è mai passato per la mente che qualcosa di così presumibilmente semplice come l'operatore == potesse essere ulteriormente ottimizzato ... mi hai interessato, darò un'occhiata a qualsiasi cosa sia ora bne.un.s. Grazie per il tuo tempo. – Wilsu