2011-12-20 15 views
59

Sono un po 'confuso su come il compilatore C# gestisce gli incrementi e i decrementi pre- e post.C# Confusioni di incrementi pre e post.

Quando il codice seguente:

int x = 4; 
x = x++ + ++x; 

x avrà il valore 10 in seguito. Penso che questo sia dovuto al fatto che il pre-incremento imposta x su 5, che lo rende 5+5 che viene valutato su 10. Quindi il post-incremento aggiornerà x a 6, ma questo valore non verrà utilizzato perché in tal caso 10 verrà assegnato a x.

Ma quando il codice I:

int x = 4; 
x = x-- - --x; 

allora x sarà 2 dopo. Qualcuno può spiegare perché questo è il caso?

+2

Ottima domanda! E abbiamo imparato che non scrivere mai codice devi pensare a cosa potrebbe fare, ma cosa farebbe. – RvdK

+15

Chiunque scriva codice come questo dovrebbe essere estratto e sparato. Non ci sono scuse per 'x = x ++ + ++ x;' ... mai. –

+15

era solo una domanda "accademica" - non scriverei mai un codice come questo :-) – Schweder

risposta

46

x-- saranno 4, ma sarà 3 al momento della --x, quindi finirà essendo 2, allora si dovrà

x = 4 - 2 

btw, il tuo primo caso sarà x = 4 + 6

Ecco un piccolo esempio che stamperà i valori per ogni parte, forse in questo modo capirete meglio:

static void Main(string[] args) 
{ 
    int x = 4; 
    Console.WriteLine("x++: {0}", x++); //after this statement x = 5 
    Console.WriteLine("++x: {0}", ++x); 

    int y = 4; 
    Console.WriteLine("y--: {0}", y--); //after this statement y = 3 
    Console.WriteLine("--y: {0}", --y); 

    Console.ReadKey(); 
} 

questo stampa o ut

x++: 4 
++x: 6 
y--: 4 
--y: 2 
+3

Grazie per la tua risposta - ho pensato che post e pre-incrementi vengono eseguiti dopo/prima della valutazione della codeline completa, ma vengono eseguiti dopo/prima della valutazione di ciascun elemento nell'espressione. – Schweder

+0

@Schweder, leggera correzione: gli operatori vengono eseguiti dopo/prima della valutazione della variabile a cui sono stati applicati. Non tutti i termini nell'espressione. – Amy

+2

@Inuyasha: correzione alla correzione: gli operatori sono * sempre * eseguiti * dopo * la valutazione della variabile come variabile. La differenza tra gli operatori pre e post è solo * il valore restituito *, non * l'ordine in cui vengono eseguite le operazioni *. –

-1

Penso che la spiegazione per il ++ + ++ caso è sbagliato:

comando ........... valore di x

.... .............. indefinito

int x = 4 .......... 4

x ++ ........... .... 5 (primo addetto è 4)

++ x ............... 6 (secondo addendo è 6)

x = summand1 + summand2 ..4 + 6 = 10

Analogamente la spiegazione del - - - caso è

comando ........... valore di x

.................. indefinita

int x = 4 .......... 4

x --............... 3 (subtactor è 4)

--x ............... 2 (subtrahend is 2)

x = subtractor-subtrahend ..4-2 = 10

+0

Non ho capito la tua risposta, scusa. –

+0

@phresnel Ho corretto un paio di errori nella risposta. In pratica sta dicendo la stessa cosa della risposta che hai accettato: In realtà ne riceviamo 10 perché stiamo aggiungendo 4 e 6; 2 è la differenza tra 4 e 2. – phoog

16

Diamo uno sguardo alla IL che viene generato da tale dichiarazione

IL_0002: ldloc.0  

carica il valore di x nello stack. Stack => (4)

IL_0003: dup   

Duplica l'elemento più in alto nella pila. Stack => (4, 4)

IL_0004: ldc.i4.1  

Inserire 1 nello stack. Stack => (1, 4, 4)

IL_0005: sub   

Sottrarre i due valori in alto e spingere il risultato in pila. Stack => (3, 4)

IL_0006: stloc.0  

Memorizza il valore più in alto dello stack su x. Stack => (4)

IL_0007: ldloc.0  

Carica il valore di x nuovamente nella pila. Stack => (3, 4)

IL_0008: ldc.i4.1  

Caricare il valore 1 nella pila. Stack => (1, 3, 4)

IL_0009: sub   

Sottrarre i due. Stack => (2, 4)

IL_000A: dup   

duplicare il valore superiore => (2, 2, 4)

IL_000B: stloc.0  

Conservare il valore superiore di nuovo a x. Stack => (2, 4)

IL_000C: sub  

Sottrarre i due valori superiori. Stack => (2)

IL_000D: stloc.0 

Memorizzare questo valore in x. x == 2

2

In questo esempio,

int x = 4; 
x = x++ + ++x; 

si può rompere le cose come:

x = 4++; which is = 5 
x = 4 + ++5; which is 4 + 6 
x = 10 

Allo stesso modo,

int x = 4; 
x = x-- - --x; 

Qui,

x = 4--; which is = 3 
x = 4 - --3; which is 4 - 2 
x = 2 

Semplicemente mettendo si può dire, sostituire il valore corrente di x, ma per ogni ++ o - aggiungere/sottrarre un valore da x.

6

La cosa più interessante che otterrete una risposta completamente diversa con C++. Compilatore netto.

int x = 4; 
x = x++ + ++x; // x = 11 
x = 4; 
x = x-- - --x; // x = -1 

Naturalmente la differenza nei risultati è determinata da diversi semantiche - sembra normale. Ma nonostante la comprensione del fatto che due compilatori .net non si comportino in modo simile per cose così elementari mi confonde anche io.

+2

In C++ (non una delle versioni di C++ non C++ di Microsoft), la modifica di una variabile più volte prima della fine dell'espressione completa produce un comportamento indefinito. –

+4

Questo non ha assolutamente nulla a che fare con * parse *. Ha a che fare con la diversa semantica permessa dai due linguaggi per quanto riguarda i punti di sequenza. –

8

Dal tuo commento:

ho pensato che post e pre-incrementi vengono eseguiti dopo/prima della valutazione del codeline completa - ma sono eseguiti dopo/prima della valutazione di ogni elemento nell'espressione.

Il tuo malinteso è estremamente comune. Nota che in alcune lingue, come C, non è specificato quando l'effetto collaterale diventa visibile ed è quindi legale, ma non obbligatorio, affinché la tua affermazione sia vera in C.

Questo non è il caso in C#; in C# effetti collaterali di codice sul lato sinistro di espressione sono sempre osservati accadere prima codice sul lato destro esegue (da un unico filo, in scenari multithreading tutte le scommesse sono spenti.)

Per una più dettagliata spiegazione di ciò che gli operatori di incremento fare in C#, vedere:

What is the difference between i++ and ++i?

ci sono un gran numero di collegamenti aggiuntivi lì ad articoli che ho scritto su questo argomento spesso fraintesa.

Problemi correlati