Perché ho i ++; io--; uno dopo l'altro?


164

Stavo guardando il codice sorgente di nmap che è stato rilasciato nel 1997 e ho notato questa sezione di codice che mi sembra un po 'strana:

int i=0, j=0,start,end;
char *expr = strdup(origexpr);
ports = safe_malloc(65536 * sizeof(short));
i++;                                         /* <<<<<< */
i--;                                         /* <<<<<< */
for(;j < exlen; j++) 
  if (expr[j] != ' ') expr[i++] = expr[j]; 
expr[i] = '\0';

Perché dovresti averlo i++;e poi i--;uno dopo l'altro? iè 0, quindi i++si trasforma iin 1. Dopodiché, i--si trasforma iin 0.

Link al codice sorgente originale. Cercare:

i++;
i--;

Qualcuno può spiegare a cosa serve?


25
Chiedi l'autore .
DaBler,

8
Immagino che facessero parte di un codice sperimentale o di debug, che l'autore ha dimenticato di rimuovere in seguito.
Nate Eldredge,

6
Il motivo è ovviamente quello di confonderti, questo è l'unico scopo :-) C'è una piccola possibilità che questo funzioni attorno ad alcuni bug del compilatore in alcuni compilatori antichi, in quel caso ci sarebbe dovuto essere un commento che ci dicesse questo motivo.
gnasher729,

18
@ RingØ: Per divertimento l'ho provato con gcc 1.27, circa 1988, su godbolt: godbolt.org/z/yYyFrQ . (Non funziona con le intestazioni di sistema moderne, quindi ho dovuto dichiarare da solo tutte le funzioni della libreria standard.) Ma con -Oesso ottimizza davvero quelle affermazioni.
Nate Eldredge,

21
Significa che il programmatore è stato pagato dalla linea ...
TonyK

Risposte:


152

Questo era un bug. Queste linee insieme risultano iinvariate, quindi non avrebbero dovuto essere lì.

L'articolo collegato che ha introdotto nmap è stato pubblicato il 1 ° settembre 1997. Se si guarda al repository SVN per nmap su https://svn.nmap.org/nmap , la revisione iniziale verificata il 10 febbraio 1998 non ha queste righe:

int i=0, j=0,start,end;
char *expr = strdup(origexpr);
char *mem = expr;

ports = safe_malloc(65536 * sizeof(short));
for(;j < exlen; j++) 
  if (expr[j] != ' ') expr[i++] = expr[j]; 
expr[i] = '\0';

Quindi questo è qualcosa che l'autore ha trovato e corretto tra la pubblicazione del codice sorgente nmap iniziale e il check-in iniziale su SVN.


1
Mmm, anche a quella pagina mancano <pre>tag attorno all'articolo; L'ispettore di Chrome rivela in che modo ciò porta a una manomissione dei documenti durante la costruzione del DOM;)
Asteroids With Wings

4
Confonde i lettori, il che è completamente indesiderato. Direi che è chiaramente un bug. ;-)
sergut

2
@sergut Wikipedia non è d'accordo con te, ma lo è anche questo post sul blog , e sono propenso anche a :-)
Toivo Säwén

4
Ora, se inon fosse un int ma una classe sofisticata con sovraccarichi dell'operatore, è possibile (sebbene improbabile e generalmente un segno di pratiche di codifica scadenti) che questo potrebbe avere alcuni effetti collaterali. (Vale solo se questo era C ++ ovviamente.)
Darrel Hoffman il

5
Forse vale la pena notare che in alcuni contesti (IO mappato in memoria), la modifica di una variabile può avere effetti esterni.
nullromo

40

È inutile. Non fa assolutamente nulla.

Se dovessi speculare, probabilmente sono i resti di alcuni codici di debug utilizzati durante lo sviluppo.

Immagino che uno dei due i++sia i--stato introdotto in un cambiamento e l'altro sia stato introdotto in un altro.

Non ho modo di trovare il punto di introduzione, tuttavia, poiché non vi era alcuna cronologia delle revisioni tra la versione di origine iniziale e la prima revisione SVN.


14
Penso che la speculazione sul codice di debug sia accurata. Ho visto così tanti diversi tipi di codice di debug solo per ottenere punti di interruzione dove li aspetti.
Nathan,

9

Per un compilatore non ottimizzante o uno che ha riconosciuto gli effetti collaterali dell'hardware, i ++; La sequenza i-- farebbe sì che io venissi letto dalla memoria, quindi riscritto, indipendentemente dal percorso seguito dal ciclo for e nidificato se.

Nell'elaborazione parallela, a volte vengono eseguiti hack del compilatore per garantire che una sequenza di codice utilizzi le proprie copie locali delle variabili anziché le copie globali.

Poiché l'esempio è uno snippet di codice, non è possibile determinare il compilatore utilizzato, il sistema operativo / hardware previsto, né se questo si trova in una sequenza / funzione di codice che è possibile eseguire come thread indipendente.

Nei sistemi più semplici, ho temporaneamente forzato le modifiche alle variabili per esercitare la funzione trap in un ambiente di debug. In tal caso, l'autore potrebbe aver dimenticato di rimuovere il codice al termine dello sviluppo.


1
allora perché non dichiararlo volatile?
vsz

6
La dichiarazione di icome variabile locale è mostrata nel codice sopra e non è possibile accedervi da un altro thread nel punto in cui i++; i--si trovano le linee.
Interjay

@vsz Penso piuttosto che intenda iessere costretto a non essere volatile. Non ho affrontato il threading in C o C ++, quindi non ho idea di come possa essere trattato come volatile e come i++; i--sopprimerlo.
Egor Hans,

volatile ha altri scopi oltre alla sicurezza del filo. Può anche essere utilizzato durante il debug per garantire che il compilatore non lo ottimizzi.
vsz

2

Ti suggerirò di controllare solo il codice aggiornato. Se usi (i = 2 + 1) subito dopo (i-1) non ha senso. Il valore di i rimane invariato. Puoi provarlo usando qualsiasi compilatore c o c ++. o anche in qualsiasi altra lingua è lo stesso. Esegui il codice nel compilatore per vedere se sbaglio o no, e fammi sapere se sto dando una risposta sbagliata.

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.