Cosa rende gli sviluppatori C così curiosi se "i ++ == ++ i"? [chiuso]


15

Solo un'osservazione casuale, sembra che su StackOverflow.com ci siano domande se "++ i == i ++". Questa domanda viene posta in ogni momento, penso di averla vista fare circa 6 o 7 volte negli ultimi 2 mesi.

Mi chiedo solo perché gli sviluppatori C sono così interessati a questo? Lo stesso concetto / domanda esiste anche per gli sviluppatori C # e Java, ma penso di aver visto solo una domanda relativa a C #.

È perché tanti esempi usano ++ i? È perché c'è qualche libro o tutorial popolare? È perché gli sviluppatori C adorano semplicemente raggruppare il più possibile in un'unica riga per "efficienza" / "prestazioni" e quindi incontrare costrutti "strani" usando l'operatore ++ più spesso?


23
(Per me come sviluppatore C #, i ++ e ++ i sono uguali. So che non lo sono, ma se scrivo un codice che dipende dalla differenza, preferirei che il refactoring sia più leggibile e mi aspetto che il compilatore e JITter si occupino di esso, ma come sviluppatore C # non sto cercando di salvare uno o due cicli di clock perché sono già relativamente inefficiente già)
Michael Stum

1
come programmatori in erba amiamo giocare con l'aritmetica, la logica e siamo curiosi di sapere come funzionano le cose. Penso che sia una grande ragione per cui a nessuno piacciono queste domande. potrebbe non essere una caratteristica pionieristica ma sicuramente è interessante! non è questo il motivo per cui siamo diventati programmatori in primo luogo ?!
Chani,

2
Ti riferisci letteralmente all'espressione ++i == i++, o più in generale alla differenza di significato tra ++ie i++?
Keith Thompson,

Risposte:


30

Sospetto che almeno in parte sia un po 'più semplice: anche adesso vediamo molte domande come questa a partire dall'inizio dell'anno scolastico e gradualmente si assottigliano nel corso dell'anno.

In quanto tale, penso sia giusto indovinare che alcuni di essi sono semplicemente il risultato di lezioni in cui l'insegnante ne parla almeno un po ', ma non spiega molto bene i suoi punti (spesso perché non li capisce davvero da solo). Soprattutto in base alle persone che sembrano porre queste domande, pochi si basano sulla codifica effettiva.


14
Non è questo l' opposto di Eternal September? Eternal September è stato quando AOL ha iniziato a offrire a Usenet l'accesso ai propri clienti, facendolo sembrare settembre (il mese in cui i nuovi studenti che hanno iniziato la scuola hanno bombardato tradizionalmente le schede come neofiti) tutto l'anno.
nlawalker,

È una teoria interessante ma forse non è sempre colpa degli insegnanti se qualcuno non capiva il materiale: forse gli studenti (1) non prestavano sufficiente attenzione durante le lezioni e (2) troppo pigri per cercare una risposta su StackOverflow prima porre di nuovo la stessa domanda.
Giorgio,

12

Perché i programmatori C DEVONO comprendere l'ordine delle operazioni. Gli sviluppatori C # non usano necessariamente gli operatori bit a bit (&, |, ~) o gli operatori di prefisso poiché siamo normalmente più preoccupati per altre cose. Tuttavia, ciò che noi sviluppatori di C # non capiamo è che dovremmo sapere cosa fanno gli operatori che utilizziamo quotidianamente e come usarli correttamente. La maggior parte di noi evita solo i luoghi in cui questo può essere un problema.

Dalla parte superiore della testa, qual è l'output di questo frammento?

    double x = 5.5;
    Console.WriteLine(x++);
    x = 5.5;
    Console.WriteLine(++x);

Direi che un buon numero di sviluppatori C # esperti non hanno idea di quale sia l'output alla Console.


3
+1. Conoscere la differenza tra gli operatori di incremento / decremento pre e post correzione è utile per situazioni come questa.
Maulrus,

4
Vedo un po 'il punto e non conosco neanche l'output (credo che sia 5.5 e 6.5, ma non ne sono sicuro), e per me non importerebbe perché lo rifotterei in x ++; Console.WriteLine (x); subito. Non sono del tutto ignorante, penso solo che sia un odore di codice grande con zero usabilità.
Michael Stum

8
La risposta alla domanda non ha nulla a che fare con l'ordine delle operazioni o la differenza tra incrementi di prefisso e postfisso. È una questione di comportamento definito e indefinito.
David Thornley,

2
L'ho incontrato oggi. Qualcosa del genere if (myList[i++] == item). Intelligente. L'ho trovato alla ricerca della fonte di un'eccezione IndexOutOfRange ... Anzi, molto "intelligente".
rmac,

6
Penso che sia 5.5 e 6.5, ma non l'ho mai visto ++usato prima su un float, e devo dire che non sembra molto appropriato. Le persone lo fanno? (Preferirei += 1)
Bart van Heukelom il

8

Penso che questo sia ovvio. In C #, per un int i, i++ == ++iè sempre falso mentre ++i == i++è sempre vero, affidabile, e chiunque sia interessato può scoprirlo facilmente semplicemente imparando le regole di C # (o addirittura semplicemente eseguendolo).

In C e C ++, d'altra parte, è quasi indefinito perché dipende dal compilatore, dall'ambiente di esecuzione, dalla piattaforma, ecc., Quindi è una domanda molto più difficile a cui rispondere, quindi molte persone lo fanno.


+1 - ma non è davvero una domanda più difficile a cui rispondere. "indefinito" è una parola. Tutta la roba "dipende da ..." è roba di cui la maggior parte delle persone non si preoccupa. Anche se stai scrivendo solo per una particolare piattaforma, dovresti usare i normali idiomi per la lingua nel suo insieme e la maggior parte degli usi degli operatori pre-incremento e post-incremento fanno parte di alcuni idiomi comuni.
Steve314,

+1: in realtà risponde alla domanda posta (ovvero, non stai leggendo tra le righe).
Thomas Eding,

7

È una domanda popolare perché è una domanda trabocchetto. Non è definito .

Il link qui sopra va a una FAQ sulla homepage di Bjarnes Stroustrup, che affronta in modo specifico questa domanda e spiega perché questo costrutto non è definito. Quello che dice è:

Fondamentalmente, in C e C ++, se leggi una variabile due volte in un'espressione in cui la scrivi anche tu, il risultato non è definito.

Avere l'ordine di valutazione indefinito è dichiarato per produrre codice con prestazioni migliori.


5

Molto probabilmente perché in C importa davvero se scrivi i++o ++iquando esegui l'aritmetica del puntatore. Lì, aumentare iprima o dopo un'operazione potrebbe essere cruciale. Ti farei un esempio, ma l'ultima volta che ho scritto C è stato 10 anni fa ...

In C #, non mi sono mai imbattuto in una situazione che mi richiederebbe di pensare i++o ++iperché AFAIK, per i cicli for / while, non importa.


3
è ancora importante capire le differenze in C # - solo perché sembra che le usi solo per / ogni loop non significa che sia l'unico posto in cui le troverai
STW

assolutamente vero.
Mladen Prajdic,

3
Questo non è rilevante per la domanda. La domanda non riguarda la differenza tra i++e ++i, ma combinandoli nella stessa espressione.
David Thornley,

@David La domanda è perché i programmatori C ne siano curiosi. La risposta (è importante in C, non tanto in C #) è completamente pertinente ".
Florian F

2

Alcuni anni fa ho letto che questi operatori erano considerati pericolosi, quindi ho cercato di scavare più informazioni su di esso. Se stackoverflow fosse stato attivo in quel momento, lo avrei chiesto lì.

Ora è perché alcune persone contorte scrivono loop come

while( [something] )
{
  a[++j] = ++j;
}

Anche ora, non sono troppo sicuro di ciò che accadrà / dovrebbe accadere, ma mi è abbastanza chiaro che più ++ [var] sulla stessa linea sta chiedendo problemi.


2
Gli incrementi hanno un comportamento indefinito come parte di un incarico in C
Tzen

7
Le assegnazioni come x = ++j;sono ben definite in C. Quanto sopra non è definito perché jviene modificato due volte senza punti di sequenza intermedi.
Matthew Flaschen,

2

Due ragioni.

L'implementazione corretta di ++ i è di incrementare i e quindi restituirlo. L'implementazione corretta di i ++ è di salvare il valore corrente, incrementare i e restituire il valore salvato. Sapere che questi non sono implementati come sinonimo è importante.

La domanda diventa quindi quando il compilatore li applica durante la valutazione di un'espressione, come l'uguaglianza.

Se il test di uguaglianza viene eseguito per primo, quindi gli operatori pre e post-incremento, dovrai scrivere una logica diversa rispetto a quando vengono valutati prima il lato sinistro (lhs) e il lato destro (rhs), quindi l'uguaglianza.

Riguarda l'ordine delle operazioni e ciò a sua volta influenza il codice che si scrive. E, non troppo sorprendentemente, non tutte le lingue sono d'accordo.

I test di base elencano ciò per consentire agli sviluppatori di verificare se i loro presupposti sono corretti e se l'implementazione effettiva corrisponde alle specifiche del linguaggio.

Questo può avere tutti i tipi di impatto quando si lavora con puntatori, loop o valori di ritorno.


5
I test di base su questo saranno fuorvianti, perché è un comportamento indefinito. Se funziona esattamente come previsto questa volta, non c'è garanzia che la prossima volta.
David Thornley,

Hai risposto alla domanda sbagliata. Dovresti rispondere perché i programmatori C ne sono curiosi.
Hugo,

Il tuo secondo para è comunque errato (almeno prima di C ++ 11): il comportamento di ++iè usare il valorei+1 e ad un certo punto nel tempo, forse prima o dopo quello, ma prima del successivo punto di sequenza, incrementoi .
MM

@MattMcNabb - Puoi indicarmi una specifica per questo, sarei curioso di sapere se le cose sono cambiate nell'implementazione. Ai tempi in cui C mappava bene sull'assembly PDP, ++ i iniettava un'istruzione INC, mentre la versione del suffisso doveva copiare il valore in un registro per usare un'istruzione dopo l'incremento. Cosa costituiva la necessità del cambiamento che hai descritto?
Walt Stoneburner,

2

Penso che sia una cosa shock culturale.

Come già sottolineato, il comportamento di un'espressione in C o C ++ può essere indefinito perché l'ordine di esecuzione dei post-incrementi ecc. Non è definito in modo rigoroso. Il comportamento indefinito è abbastanza comune in C e, naturalmente, molto è stato importato in C ++.

Per qualcuno che ha programmato in un'altra lingua - qualcuno che ha preso l'idea che i linguaggi di programmazione dovrebbero essere precisi e che i computer dovrebbero fare ciò che gli viene detto di fare ... beh, è ​​uno shock scoprire che C è intenzionalmente vago su alcune cose.


C è in questo modo perché è stato progettato per supportare molte più piattaforme di quanto esistesse anche quando è stato definito C #, comprese le più strane piattaforme embedded o mainframe a cui puoi pensare. C #, d'altra parte, gira su ... x86 e 360? forse anche ARM? Nient'altro. Ecco perché C # può definire molto di più.
DeadMG

++ Inoltre, C non è stato creato per la prima volta su un PDP-11? Dove c'erano le istruzioni di incremento automatico? C voleva essere "vicino alla macchina" in modo da poter fare un utile uso del set di istruzioni.
Mike Dunlavey,

@MikeDunlavey: No, i C ++e gli --operatori non erano basati sul PDP-11, che non esisteva quando quegli operatori furono introdotti nel linguaggio precedente di C B. Vedi cm.bell-labs.com/who/dmr/chist.html e cerca "auto-increment".
Keith Thompson,

1

Forse è solo che gli sviluppatori C usano l'incremento ++ più spesso in generale, visto che C non ha "foreach" o dichiarazioni simili per iterare attraverso le matrici. Oh, e naturalmente puntatore aritmico, come già accennato!


1
Buon punto, ho dimenticato che foreach è un concetto relativamente moderno.
Michael Stum

-1

La differenza tra le due parti: il post e il preincrement stanno funzionando nel modo in cui queste due parti di codice dovrebbero funzionare in ogni lingua. QUESTO NON È DIPENDENTE DALLA LINGUA !!!

++i

Questo è pre-incremento. Questo pezzo di codice aumenterà prima il valore di iprima di inviare il valore alla riga in cui viene utilizzato.

i++

Questo è l'incremento post. Questo pezzo di codice restituirà il valore di iprima che aumenti il ​​valore dii sulla riga in cui viene utilizzato.

In un altro piccolo esempio:

int main(void)
{
  int i = 0; 
  int result; 
  result = 10 + ++i; 
  printf("%d \n", result); // = 11 

  int j = 0; 
  result = 10 + j++; 
  printf("%d \n", result);// = 10
  return 0;
}

Questo codice viene compilato con risultati sul codepad.

Ciò ha a che fare con l'implementazione interna del sovraccarico dell'operatore.

++i aumenta direttamente il valore (ed è quindi un po 'più veloce)

i++crea innanzitutto una copia che viene restituita nel punto in cui è necessario e successivamente il valore originale della ivariabile viene aumentato di uno.

Spero che questo sia chiaro ora.


Tuttavia, questo non risolve la vera domanda: perché gli sviluppatori C chiedono questo più di altri. L'OP comprende gli operatori.
Martijn Pieters,

Anche questa risposta è effettivamente errata. ++inon è più veloce e i++non crea una copia. Inoltre, ++isi comporta in modo leggermente diverso in C rispetto a C ++, figuriamoci tra altre lingue.
MM,
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.