Warum habe ich ++; ich--; gleich nacheinander?

164

Ich habe mir den Quellcode für nmap angesehen , der 1997 veröffentlicht wurde, und mir ist dieser Codeabschnitt aufgefallen, der für mich etwas seltsam aussieht:

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';

Warum hättest du i++;und dann i--;direkt nacheinander? iist 0, i++dreht sich dann izu 1. Danach i--dreht sich ium 0.

Link zum ursprünglichen Quellcode. Suchen nach:

i++;
i--;

Kann jemand erklären, wofür das ist?

DDiamond
quelle
25
Fragen den Autor .
DaBler
8
Ich würde vermuten, dass sie Teil eines experimentellen oder Debugging-Codes waren, den der Autor später vergessen hatte, zu entfernen.
Nate Eldredge
6
Der Grund ist offensichtlich, Sie zu verwirren, das ist der einzige Zweck :-) Es besteht eine geringe Wahrscheinlichkeit, dass dies einen Compiler-Fehler in einem alten Compiler umgeht. In diesem Fall hätte es einen Kommentar geben müssen, der uns diesen Grund erklärt.
gnasher729
18
@ RingØ: Zum Spaß habe ich es mit gcc 1.27, circa 1988, auf godbolt versucht: godbolt.org/z/yYyFrQ . (Es funktioniert nicht mit modernen System-Headern, daher musste ich alle Standard-Bibliotheksfunktionen selbst deklarieren.) Aber -Odamit werden diese Anweisungen tatsächlich optimiert.
Nate Eldredge
21
Dies

Antworten:

152

Das war ein Fehler. Diese Zeilen zusammen führen idazu, dass sie unverändert bleiben, also hätten sie nicht dort sein dürfen.

Der verlinkte Artikel, in dem nmap eingeführt wurde, wurde am 1. September 1997 veröffentlicht. Wenn Sie sich das SVN-Repository für nmap unter https://svn.nmap.org/nmap ansehen , enthält die am 10. Februar 1998 eingecheckte Erstrevision nicht die folgenden Zeilen:

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';

Dies ist also etwas, das der Autor zwischen der Veröffentlichung des anfänglichen nmap-Quellcodes und dem ersten Einchecken in SVN gefunden und behoben hat.

dbush
quelle
1
Hmm, auf dieser Seite fehlen auch <pre>Tags um den Artikel; Der Inspektor von Chrome zeigt, wie dies dazu führt, dass Dokumente während der DOM-Erstellung beschädigt werden;)
Asteroids With Wings
4
Es verwirrt die Leser, was völlig unbeabsichtigt ist. Ich würde sagen, es ist eindeutig ein Fehler. ;-)
Sergut
2
@sergut Wikipedia stimmt Ihnen nicht zu, aber dieser Blog-Beitrag tut es, und ich bin auch dazu geneigt :-)
Toivo Säwén
4
Wenn ies sich nicht um eine int-Klasse handelt, sondern um eine ausgefallene Klasse mit Operatorüberladungen, ist es möglich (obwohl dies unwahrscheinlich und im Allgemeinen ein Zeichen für schlechte Codierungspraktiken ist), dass dies einige Nebenwirkungen haben kann. (Gilt natürlich nur für C ++.)
Darrel Hoffman
5
Es ist vielleicht erwähnenswert, dass das Ändern einer Variablen in einigen Kontexten (speicherabgebildete E / A) externe Auswirkungen haben kann.
nullromo
40

Es ist sinnlos. Es macht absolut nichts.

Wenn ich spekulieren sollte, sind es wahrscheinlich die Überreste eines Debugging-Codes, der während der Entwicklung verwendet wurde.

Ich vermute, dass einer von beiden i++ oder i--in einer Änderung eingeführt wurde und der andere in einer anderen eingeführt wurde.

Ich habe jedoch keine Möglichkeit, den Einführungspunkt zu finden, da zwischen der ersten Quellversion und der ersten SVN-Revision kein Revisionsverlauf bestand.

SS Anne
quelle
14
Ich denke, die Spekulationen über das Debuggen von Code sind richtig. Ich habe so viele verschiedene Arten von Debugging-Code gesehen, nur um Haltepunkte dort zu erhalten, wo Sie sie erwarten.
Nathan Goings
9

Für einen nicht optimierenden Compiler oder einen, der Hardware-Nebenwirkungen erkannt hat, ist i ++; Die i-- -Sequenz würde dazu führen, dass i aus dem Speicher gelesen und dann neu geschrieben wird, unabhängig vom Pfad, der durch die for-Schleife genommen und verschachtelt wird, wenn.

Bei der Parallelverarbeitung werden manchmal Compiler-Hacks durchgeführt, um sicherzustellen, dass eine Codesequenz ihre eigenen lokalen Kopien von Variablen anstelle globaler Kopien verwendet.

Da es sich bei dem Beispiel um ein Code-Snippet handelt, kann weder der verwendete Compiler noch das erwartete Betriebssystem / die erwartete Hardware oder die Codesequenz / -funktion ermittelt werden, die als unabhängiger Thread ausgeführt werden kann.

In einfacheren Systemen habe ich vorübergehend Änderungen an Variablen erzwungen, um die Trap-Funktion in einer Debugging-Umgebung auszuführen. In diesem Fall hat der Autor möglicherweise vergessen, den Code nach Abschluss der Entwicklung zu entfernen.

Larry Fisher
quelle
1
Warum dann nicht einfach als volatil deklarieren?
vsz
6
Die Deklaration ials lokale Variable wird im obigen Code angezeigt, und ein anderer Thread kann an der Stelle, an der sich die i++; i--Zeilen befinden, auf keinen Fall darauf zugreifen.
Zwischenzeit
@vsz Ich denke eher, er meint, er isei gezwungen, nichtflüchtig zu sein. Ich habe mich jedoch nicht mit Threading in C oder C ++ befasst, daher habe ich keine Ahnung, wie es als flüchtig behandelt werden könnte und wie i++; i--dies unterdrückt werden würde.
Egor Hans
flüchtig hat neben der Gewindesicherheit noch andere Zwecke. Es kann auch beim Debuggen verwendet werden, um sicherzustellen, dass der Compiler es nicht entfernt.
vsz
2

Ich werde Ihnen vorschlagen, nur den aktualisierten Code zu überprüfen. Wenn Sie direkt danach (i = 2 + 1) (i-1) verwenden, ergibt dies keinen Sinn. Der Wert von i bleibt unverändert. Sie können es mit einem beliebigen c- oder c ++ - Compiler versuchen. oder sogar in einer anderen Sprache ist es dasselbe. Führen Sie den Code im Compiler aus, um festzustellen, ob ich falsch oder richtig bin, und lassen Sie mich wissen, wenn ich eine falsche Antwort gebe.

TripleM
quelle