Che cos'è x dopo “x = x ++”?


285

Cosa succede (dietro le tende) quando questo viene eseguito?

int x = 7;
x = x++;

Cioè, quando una variabile viene post incrementata e assegnata a se stessa in un'istruzione? Ho compilato ed eseguito questo. xè ancora 7 anche dopo l'intera affermazione . Nel mio libro, dice che xè aumentato!


9
Prova questo: int x = 7; x = ++x;ovviamente è ancora un codice orribile, non è necessario riassegnarlo. int x = 7; x++;è abbastanza.
stivlo,

7
Questa è una brutta pratica, non incrementare la variabile nella stessa riga in cui la usi.
Yousf,

5
Preferirei usare x += 1, tranne forse nei loop. for(int x=0; x<7; x++)
Svish,

2
@andyortlieb non c'è nessun oggetto, solo un valore di base.
fortran,

Risposte:


301

xviene incrementato. Ma stai assegnando il vecchio valore del xritorno a se stesso.


x = x++;
  1. x++incrementa xe restituisce il suo vecchio valore.
  2. x = assegna il vecchio valore a se stesso.

Quindi, alla fine, xviene assegnato al suo valore iniziale.


3
Quindi, cosa dirai di x = ++ x;
Hisham Muneer,

3
@HishamMuneer xviene incrementato prima di essere letto in quel caso, quindi si finisce con x + 1.

@HishamMuneer È troppo tardi. Ma lo sto mettendo qui perché potrebbe essere utile per altre persone che guarderanno in futuro. Il modo migliore per capire questo problema è guardare il codice assembly creato per x = x ++ e x = ++ x. Vedi anche la risposta di Thinkingcap.
nantitv,

So che questo è super vecchio, ma ho una domanda. Il suddetto ordine di funzionamento è garantito dalla norma? È possibile che l'assegnazione venga eseguita prima dell'incremento?
Emerald Weapon,

@EmeraldWeapon È definito in Java. È solo in C / C ++ vedi quel tipo di shenanigans.
Mistico il

385
x = x++;

è equivalente a

int tmp = x;
x++;
x = tmp;

46
Lol, yay per definizioni ricorsive. probabilmente avresti dovuto farlo x=x+1invece dix++
user606723,

8
@ user606723: No. Intendevo l'intera istruzione x = x++, non solo l'incremento del post x++.
Prince John Wesley,

20
Non penso che sia così utile senza ulteriori spiegazioni. Ad esempio, non è vero che x = ++x;sia anche equivalente a int tmp = x; ++x; x = tmp;, quindi da quale logica possiamo dedurre che la tua risposta è corretta (quale è)?
kvb,

4
ancora più chiaro è in asm x=x++ =MOV x,tmp; INC x; MOV tmp,x
forker

3
@forker: penso che sarebbe più chiaro se tu usassi le istruzioni di assemblaggio che si applicano al processore che Michael sta usando;)
Carl,

258

La dichiarazione:

x = x++;

è equivalente a:

tmp = x;   // ... this is capturing the value of "x++"
x = x + 1; // ... this is the effect of the increment operation in "x++" which
           //     happens after the value is captured.
x = tmp;   // ... this is the effect of assignment operation which is
           //     (unfortunately) clobbering the incremented value.

In breve, l'affermazione non ha alcun effetto.

I punti chiave:

  • Il valore di un'espressione di incremento / decremento Postfix è il valore dell'operando prima che abbia luogo l'incremento / decremento. (Nel caso di un modulo Prefisso, il valore è il valore dell'operando dopo l'operazione,)

  • l'RHS di un'espressione di assegnazione viene completamente valutata (inclusi eventuali incrementi, decrementi e / o altri effetti collaterali) prima che il valore venga assegnato all'LHS.

Si noti che, diversamente da C e C ++, l'ordine di valutazione di un'espressione in Java è totalmente specificato e non c'è spazio per variazioni specifiche della piattaforma. I compilatori sono autorizzati a riordinare le operazioni solo se ciò non modifica il risultato dell'esecuzione del codice dalla prospettiva del thread corrente. In questo caso, un compilatore sarebbe autorizzato a ottimizzare l'intera istruzione perché si può dimostrare che è una no-op.


Nel caso in cui non sia già ovvio:

  • "x = x ++;" è quasi certamente un errore in qualsiasi programma.
  • L'OP (per la domanda originale!) Probabilmente significava "x ++;" anziché "x = x ++;".
  • Le istruzioni che combinano incremento / decremento automatico e assegnazione sulla stessa variabile sono difficili da comprendere, e quindi dovrebbero essere evitate indipendentemente dalla loro correttezza . Semplicemente non è necessario scrivere codice del genere.

Si spera che controllori di codice come FindBugs e PMD contrassegnino il codice come questo come sospetto.


7
Come nota a margine, OP, probabilmente intendi semplicemente dire x++invece di x = x++.
Jon Newmuis,

3
Corretto, ma forse sottolineare che l'incremento avviene dopo la valutazione dell'espressione della mano destra, ma pre- assegnazione al lato sinistro, quindi l'apparente "sovrascrittura"
Boemia

2
sembra uno di quei twister di programmazione del liceo ... bello chiarire le tue basi!
Kumarharsh,

1
@Alberto - È bello sapere che non prendi dichiarazioni "esperte" come "verità evangelica". Tuttavia, un modo migliore per convalidare ciò che ho detto sarebbe consultare il JLS. Il test di compilazione / decompilazione mostra solo che ciò che ho detto è valido per un compilatore Java. Altri potrebbero (ipoteticamente) comportarsi diversamente ... tranne per il fatto che il JLS non lo consente.
Stephen C,

4
Solo un FYI: questo è stato originariamente pubblicato per una domanda diversa, che è stata chiusa come duplicata di questa e ora è stata unita.
Shog9,

33
int x = 7;
x = x++;

Ha un comportamento indefinito in C e per Java vedere questa risposta . Dipende dal compilatore cosa succede.


4
No, non dipende dal compilatore in base alla risposta che hai citato - per favore modifica - -1 per ora
Mr_and_Mrs_D

@Mr_and_Mrs_D Quindi dipende da cosa?
Mac

2
È un comportamento indefinito_solo per C_. Anche così dire che dipende dal compilatore è fuorviante - implica che il compilatore dovrebbe in qualche modo specificare questo comportamento. Ripristino il mio voto ma prendo in considerazione la modifica della tua risposta - modifica: oops non posso - devi prima modificarlo: D
Mr_and_Mrs_D

16

Un costrutto come x = x++;indica che probabilmente stai fraintendendo ciò che l' ++operatore fa:

// original code
int x = 7;
x = x++;

Riscriviamo questo per fare la stessa cosa, in base alla rimozione ++dell'operatore:

// behaves the same as the original code
int x = 7;
int tmp = x; // value of tmp here is 7
x = x + 1; // x temporarily equals 8 (this is the evaluation of ++)
x = tmp; // oops! we overwrote y with 7

Ora, riscriviamolo per fare (quello che penso) che volevi:

// original code
int x = 7;
x++;

La sottigliezza qui è che l' ++operatore modifica la variabilex , a differenza di un'espressione come x + x, che valuterebbe un valore int ma lascerebbe xinvariata la variabile stessa. Considera un costrutto come il venerabile forloop:

for(int i = 0; i < 10; i++)
{
    System.out.println(i);
}

Notate il i++dentro? È lo stesso operatore. Potremmo riscrivere questo forciclo in questo modo e si comporterebbe lo stesso:

for(int i = 0; i < 10; i = i + 1)
{
    System.out.println(i);
}

Consiglio anche di non utilizzare l' ++operatore in espressioni più grandi nella maggior parte dei casi. A causa della sottigliezza di quando modifica la variabile originale in pre-post-incremento ( ++xe x++, rispettivamente), è molto facile introdurre bug sottili che sono difficili da rintracciare.


13

Secondo il codice byte ottenuto dai file di classe,

Entrambe le assegnazioni incrementano x, ma la differenza è la tempistica di when the value is pushed onto the stack

In Case1, Push si verifica (e quindi in seguito assegnato) prima dell'incremento (essenzialmente significa che l'incremento non fa nulla)

In Case2, l'incremento si verifica prima (rendendolo 8) e quindi viene inserito nello stack (e quindi assegnato a x)

Caso 1:

int x=7;
x=x++;

Codice byte:

0  bipush 7     //Push 7 onto  stack
2  istore_1 [x] //Pop  7 and store in x
3  iload_1  [x] //Push 7 onto stack
4  iinc 1 1 [x] //Increment x by 1 (x=8)
7  istore_1 [x] //Pop 7 and store in x
8  return       //x now has 7

Caso 2:

int x=7; 
x=++x;

Codice byte

0  bipush 7     //Push 7 onto stack
2  istore_1 [x] //Pop 7 and store in x
3  iinc 1 1 [x] //Increment x by 1 (x=8)
6  iload_1  [x] //Push x onto stack
7  istore_1 [x] //Pop 8 and store in x
8  return       //x now has 8
  • Stack qui si riferisce a Stack di operando, locale: x indice: 1 tipo: int

Puoi per favore spiegare la tua risposta in dettaglio.
Nihar

Dai

8

Viene incrementato dopo " x = x++;". Sarebbe 8 se lo facessi " x = ++x;".


4
Se viene incrementato dopo x = x++, dovrebbe essere 8.
R. Martinho Fernandes l'

8

L'operatore Post Increment funziona come segue:

  1. Memorizza il valore precedente dell'operando.
  2. Incrementa il valore dell'operando.
  3. Restituisce il valore precedente dell'operando.

Quindi la dichiarazione

int x = 7;
x = x++; 

sarebbe valutato come segue:

  1. x è inizializzato con valore 7
  2. l'operatore post increment memorizza il valore precedente di x ie 7 per restituirlo.
  3. Incrementa la x, quindi ora x è 8
  4. Restituisce il valore precedente di x ie 7 e viene assegnato di nuovo a x, quindi x diventa di nuovo 7

Quindi x è effettivamente aumentato, ma poiché x ++ sta assegnando il risultato a x, il valore di x viene sovrascritto al valore precedente.


Ma in msvc x è 8. Sì in gcc e clang x è 7.
Summer Sun

7

L'incremento si verifica dopo la chiamata di x, quindi x è uguale a 7. ++ x sarebbe uguale a 8 quando viene chiamata x


7

Quando riassegni il valore per xè ancora 7. Prova x = ++xe otterrai 8 altro

x++; // don't re-assign, just increment
System.out.println(x); // prints 8

6

perché x ++ incrementa il valore DOPO averlo assegnato alla variabile. così via e durante l'esecuzione di questa linea:

x++;

varialbe x avrà ancora il valore originale (7), ma usando di nuovo x su un'altra riga, come

System.out.println(x + "");

ti darà 8.

se si desidera utilizzare un valore incrementato di x sull'istruzione di assegnazione, utilizzare

++x;

Questo aumenterà x di 1, POI assegna quel valore alla variabile x.

[Modifica] invece di x = x ++, è solo x ++; il primo assegna il valore originale di x a se stesso, quindi in realtà non fa nulla su quella linea.


Quello che dice che incrementa dopo l'assegnazione e quello che dice che stamperà 8. Si incrementa prima di assegnare e stampa 7.
R. Martinho Fernandes,

se x è originariamente 7, System.out.println (String.valueOf (x ++)); stampe 7. sei sicuro che stiamo parlando dello stesso linguaggio di programmazione?
josephus l'

Sì, lo sono. Questo ideone.com/kj2UU non stampa 8, come afferma questa risposta.
R. Martinho Fernandes,

si, ho sbagliato. x = x ++ assegnerà da 7 a x prima di incrementare x. poiché x ++ (che è un compito in sé) si risolve prima di x = (qualunque cosa), seguirà il valore assegnato a x in x = (qualunque cosa). scusa non l'ho visto.
josephus l'

1
In realtà, l'incremento è la prima cosa che succede. ideone.com/xOIDU
R. Martinho Fernandes,

4

Cosa succede quando int x = 7; x = x++;?

ans -> x++significa prima utilizzare il valore di x per l'espressione e quindi aumentarlo di 1.
Questo è ciò che accade nel tuo caso. Il valore di x su RHS viene copiato nella variabile x su LHS e quindi il valore di xviene aumentato di 1.

Allo stesso modo ++x significa ->aumentare il valore di x prima di uno e quindi utilizzare in espressione.
Quindi, nel tuo caso, se lo fai x = ++x ; // where x = 7
otterrai un valore di 8.

Per maggiore chiarezza, prova a scoprire quante istruzioni printf eseguiranno il seguente codice

while(i++ <5)   
  printf("%d" , ++i);   // This might clear your concept upto  great extend

non corretto "Il valore di x su RHS viene copiato nella variabile x su LHS e quindi il valore di x viene aumentato di 1" - questo farebbe xessere 8, ma è 7 - l'incremento avviene tra lettura e assegnazione
user85421

3

++xè pre-incremento ->x viene incrementato prima dell'uso
x++è post-incremento ->x viene incrementato dopo l'uso

int x = 7; -> x get 7 value <br>
x = x++; -> x get x value AND only then x is incremented

1

Quindi questo significa: x++non è uguale ax = x+1

perché:

int x = 7; x = x++;
x is 7

int x = 7; x = x = x+1;
x is 8

e ora sembra un po 'strano:

int x = 7; x = x+=1;
x is 8

molto dipendente dal compilatore!


2
chi ha detto che era uguale in primo luogo?
fortran,

1
Se fossi in te cestinerei immediatamente questi libri xD In ogni caso, sarebbe come (x = x + 1, x-1)in C, dove sono consentite espressioni separate da virgola.
fortran,

3
@fortran: Beh, nella mia copia decennale di "The Java Programming Language, Third Edition" a pagina 159 dice "" L'espressione i ++ è equivalente a i = i + 1 tranne per il fatto che sono valutata una sola volta ". in primo luogo, James Gosling, sembrerebbe. Questa parte di questa edizione delle specifiche Java è straordinariamente vaga e poco specificata; presumo che le edizioni successive abbiano ripulito il linguaggio per esprimere più chiaramente la semantica dell'operatore reale
Eric Lippert

2
@fortran: con "tranne i viene valutato solo una volta" lo standard sta tentando di comunicare che un'espressione come "M (). x ++" chiama M () solo una volta. Una formulazione meno vaga e più accurata enfatizzerebbe che esiste una differenza tra la valutazione di i come variabile per determinare la sua posizione di memorizzazione - che è ciò che si intende per "valutato solo una volta" qui - e la lettura o la scrittura in quella posizione di archiviazione - - una delle due potrebbe essere un'interpretazione ragionevole ma errata di "valutato". Chiaramente il luogo di archiviazione deve essere sia letto che scritto!
Eric Lippert,

1
"molto dipendente dal compilatore" - Niente affatto!
Stephen C,

-1

x = x ++;

Questo è l'operatore post-incremento. Dovrebbe essere inteso come "Usa il valore dell'operando e quindi incrementa l'operando".

Se si desidera che avvenga il contrario, ovvero "Incrementa l'operando e quindi utilizza il valore dell'operando", è necessario utilizzare l'operatore di pre-incremento come mostrato di seguito.

x = ++ x;

Questo operatore prima incrementa il valore di x di 1 e quindi assegna il valore a x.


-1

Penso che questa controversia possa essere risolta senza entrare nel codice e pensare.

Considera i ++ e ++ i come funzioni, ad esempio Func1 e Func2.

Ora i = 7;
Func1 (i ++) restituisce 7, Func2 (++ i) restituisce 8 (lo sanno tutti). Internamente entrambe le funzioni incrementano da i a 8, ma restituiscono valori diversi.

Quindi i = i ++ chiama la funzione Func1. All'interno della funzione i aumenta a 8, ma al termine la funzione restituisce 7.

Quindi alla fine 7 viene assegnato a i. (Quindi alla fine, i = 7)


2
Non vi è alcuna "controversia" valida qui. Il codice si comporta in modo dimostrabile in un modo particolare e il comportamento è conforme a JLS. Chiunque pensi che si comporti in modo diverso o non l'ha provato o è illuso. (È un po 'come dire che 7 x 7 è 49 è "controverso" quando qualcuno ha dimenticato i loro orari ...)
Stephen C,

-2

Questo perché hai usato un operatore post-incremento. In questa seguente riga di codice

x = x++;

Quello che succede è che stai assegnando il valore di x a x. x ++ incrementa x dopo che il valore di x è assegnato a x. Ecco come funzionano gli operatori post-incremento. Funzionano dopo che è stata eseguita una dichiarazione. Quindi nel tuo codice, x viene restituito prima dopo, quindi viene incrementato.

Se avete fatto

x = ++x;

La risposta sarebbe 8 perché hai usato l'operatore di pre-incremento. Ciò incrementa il valore prima di restituire il valore di x.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.