Pourquoi avoir i ++; je--; l'un après l'autre?

164

Je regardais le code source de nmap qui a été publié en 1997 et j'ai remarqué cette section de code qui me semble un peu étrange:

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

Pourquoi auriez-vous i++;et puis i--;juste après l'autre? iest 0, puis i++se tourne ivers 1. Après cela, i--se tourne ivers 0.

Lien vers le code source d'origine. Rechercher:

i++;
i--;

Quelqu'un peut-il expliquer à quoi cela sert?

DDiamond
la source
25
Demandez à l'auteur .
DaBler
8
Je suppose qu'ils faisaient partie d'un code expérimental ou de débogage, que l'auteur a oublié de supprimer par la suite.
Nate Eldredge
6
La raison est évidemment de vous confondre, c'est le seul but :-) Il y a une petite chance que cela fonctionne autour d'un bug de compilation dans un ancien compilateur, dans ce cas, il aurait dû y avoir un commentaire nous expliquant cette raison.
gnasher729
18
@ RingØ: Pour le plaisir, je l'ai essayé avec gcc 1.27, vers 1988, sur godbolt: godbolt.org/z/yYyFrQ . (Cela ne fonctionne pas avec les en-têtes système modernes, j'ai donc dû déclarer toutes les fonctions de bibliothèque standard moi-même.) Mais -Ocela optimise effectivement ces instructions.
Nate Eldredge
21
Cela signifie que le programmeur a été payé par la ligne ...
TonyK

Réponses:

152

C'était un bug. Ensemble, ces lignes restent iinchangées, donc elles n'auraient pas dû être là.

L'article lié qui a introduit nmap a été publié le 1er septembre 1997. Si vous consultez le référentiel SVN pour nmap à https://svn.nmap.org/nmap , la révision initiale archivée le 10 février 1998 n'a pas ces lignes:

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

C'est donc quelque chose que l'auteur a trouvé et corrigé entre la publication du code source nmap initial et l'archivage initial sur SVN.

dbush
la source
1
Hmm cette page manque également de <pre>balises autour de l'article; L'inspecteur de Chrome révèle comment cela conduit à des manipulations de documents lors de la construction du DOM;)
Asteroids With Wings
4
Cela déroute les lecteurs, ce qui n'est pas du tout prévu. Je dirais que c'est clairement un bug. ;-)
sergut
2
@sergut Wikipedia n'est pas d'accord avec vous, mais cet article de blog le fait, et je suis également enclin à le faire :-)
Toivo Säwén
4
Maintenant, si ce in'était pas un int mais une classe sophistiquée avec des surcharges d'opérateurs, il est possible (bien que peu probable et généralement un signe de mauvaises pratiques de codage) que cela puisse avoir des effets secondaires. (S'applique uniquement si c'était du C ++ bien sûr.)
Darrel Hoffman
5
Il convient peut-être de noter que dans certains contextes (E / S mappées en mémoire), la modification d'une variable peut avoir des effets externes.
nullromo
40

C'est inutile. Cela ne fait absolument rien.

Si je devais spéculer, c'est probablement les restes d'un code de débogage qui a été utilisé pendant le développement.

Je suppose que l'un i++ou l'autre a i--été introduit dans un changement et l'autre dans un autre.

Je n'ai aucun moyen de trouver le point d'introduction, car il n'y avait pas d'historique de révision entre la version source initiale et la première révision SVN.

SS Anne
la source
14
Je pense que la spéculation sur le débogage du code est exacte. J'ai vu tellement de types différents de code de débogage juste pour obtenir des points d'arrêt là où vous les attendez.
Nathan Goings
9

Pour un compilateur non optimisant, ou un compilateur qui reconnaît les effets secondaires du matériel, l'i ++; La séquence i-- entraînerait la lecture de i dans la mémoire, puis sa réécriture, quel que soit le chemin emprunté par la boucle for et imbriqué if.

Dans le traitement parallèle, des hacks de compilation sont parfois effectués pour garantir qu'une séquence de code utilise ses propres copies locales de variables plutôt que des copies globales.

Étant donné que l'exemple est un extrait de code, on ne peut pas déterminer le compilateur utilisé, le système d'exploitation / matériel attendu, ni s'il s'agit d'une séquence / fonction de code qui peut être exécutée en tant que thread indépendant.

Dans les systèmes plus simples, j'ai temporairement forcé des modifications de variables pour exercer la fonction d'interruption dans un environnement de débogage. Si tel était le cas, l'auteur aurait peut-être oublié de supprimer le code une fois le développement terminé.

Larry Fisher
la source
1
alors pourquoi ne pas simplement le déclarer volatile?
vsz
6
La déclaration de en itant que variable locale est indiquée dans le code ci-dessus, et il n'y a aucun moyen d'y accéder par un autre thread au point où se trouvent les i++; i--lignes.
7h17
@vsz Je pense plutôt qu'il veut dire qu'il iest forcé d'être non volatile. Cependant, je n'ai pas traité du filetage en C ou C ++, donc je n'ai aucune idée de comment il pourrait être traité comme volatile et comment i++; i--supprimer cela.
Egor Hans
volatile a d'autres fonctions que la sécurité des threads. Il peut également être utilisé lors du débogage pour garantir que le compilateur ne l'optimisera pas.
vsz
2

Je vous suggère de vérifier uniquement le code mis à jour. Si vous utilisez (i = 2 + 1) juste après (i-1), cela n'a aucun sens. La valeur de i reste inchangée. Vous pouvez l'essayer en utilisant n'importe quel compilateur c ou c ++. ou même dans une autre langue, c'est la même chose. Exécutez le code dans le compilateur pour voir si j'ai tort ou raison et faites-moi savoir si je donne une mauvaise réponse.

TripleM
la source