2009-11-03 1 views
11

Ho appena notato che, dato il seguente codice:Compilatore magico: perché?

if (x.ID > 0 && !x.IsCool) 

Microsoft C# 3.0 (VS2008 SP1) compilatore di ottimizzare a questo:

if (!((x.Id <= 0) || x. IsCool)) 

Questo è il debug senza ottimizzazione abilitata . Perché il compilatore lo fa? È più veloce in termini di esecuzione?

ho usato Reflector per scoprirlo (in realtà stavo cercando qualcosa di diverso)

+8

Come l'hai scoperto? –

+1

E cosa succede con un getter che induce effetti collaterali? :) –

+0

@ pst: gli effetti collaterali sui getter possono essere ignorati dal compilatore. Fondamentalmente, il compilatore non può assumere effetti collaterali su getter e setter. –

risposta

49

Il compilatore C# sicuramente non genera un codice C# equivalente per lo snippet. È compilato fino a IL. Fondamentalmente, quello che stai vedendo (da Reflector, immagino) è l'equivalente codice C# che un decompilatore sputa fuori per quell'IL:.

  1. Le specifiche della lingua non dicono che sia un codice "non ottimizzato". Il compilatore C# è autorizzato a generare qualsiasi codice valido e funzionalmente equivalente. Anche senza l'ottimizzazione, il compilatore potrebbe eseguire ottimizzazioni di base. Inoltre, non si può dire cosa è naturale per il compilatore e se il compilatore l'ha volutamente ottimizzato o no.

  2. L'istruzione if viene valutata come una sequenza di rami condizionali in base ai valori di ogni singola espressione specificata nella clausola "e".L'espressione è non valutata in un unico blocco di codice con istruzioni "e". L'output del decompilatore è qualcosa di inferito da quei rami. Il decompilatore non può sempre dedurre l'espressione originale che hai scritto. Produce solo qualcosa di equivalente.

Allo stesso modo, la differenza tra questo frammento:

if (a) { something(); } 
else { somethingElse(); } 

e questo frammento:

if (!a) { somethingElse(); } 
else { something(); } 

non è qualcosa che ci si distinguono per vedere il codice compilato.

+3

+1 Questa è la risposta giusta e spiegata sinteticamente per l'avvio. :) –

+1

Non volevo se questo in realtà è un "ottimizzazione" (quindi le virgolette). È il || valori insieme che mi stavo chiedendo. Pensavo che l'IL avrebbe usato operazioni booleane e/e reali, ma non è questo il caso. sotto il cofano si usa solo una combinazione di ble.s, br.s e brtrue.s. –

8

Penso che queste due espressioni sono esattamente equivalenti da un punto di vista semantica del linguaggio. Entrambe le modalità comportano il cortocircuito.

Sono un po 'sbalordito che la risposta di Andrew ha già dieci upvotes; sembra un'assurdità per me, ma forse mi manca davvero qualcosa di sottile qui.

EDIT

Quindi, solo per riassumere:

domanda del PO chiede "perché questo accada di ottimizzazione".

Infatti non si verifica alcuna "ottimizzazione". I due codici sorgente C# sono logicamente equivalenti. ".Net Reflector" o qualsiasi altro strumento di disassemblaggio è probabilmente in grado di decompilare lo stesso IL in uno o nell'altro. A livello di IL, ci sono solo un sacco di salti condizionali, e quindi non c'è necessariamente un modo per sapere "quale strada è se e che altro" o altre equivalenze simili di DeMorgan.

Affascinanti, le persone sono estremamente felici di votare su o giù per le risposte a questa domanda, anche quando (o forse perché) la domanda originale non ha molto senso (o si basa su un'ipotesi errata).

Fortunatamente, alla fine prevale la saggezza della folla (e di individui intelligenti come @Mehrdad). Evviva per StackOverflow!

(Sto facendo la mia risposta una wiki, perché non voglio un rappresentante per "storytelling su una domanda" quando il rappresentante dovrebbe essere assegnato a "buone risposte a una domanda" .Penso che la storia di questa domanda sia interessante.)

+3

@Brian - Sono rimasto sbalordito anche considerando il fatto che ero al 100% scorretto :) Questo è quello che ottengo per la pubblicazione off-the -cuff come quello senza pensare. –

+0

Hai perfettamente ragione, una distinzione tra maiuscole e minuscole rivela che gli ** rami stessi sono generati da entrambi i codici, quindi lo stesso cortocircuito. Tuttavia, questo è sottile e a prima vista ho effettivamente pensato che Andrew avesse ragione (poi ho fatto tutti i casi nella mia testa). –

+1

:) Sono contento che il design di StackOverflow (modifica, stile wiki, votazione) significhi che alla fine tutto funzioni, anche se può essere un giro sulle montagne russe durante i primi minuti di una domanda. :) – Brian

6

Il se compila per un opcode di salto condizionale. Sollevare la negazione dall'espressione consente di ottimizzarlo scambiando il target di salto condizionale con il blocco di caduta attraverso.