Почему я ++; я--; сразу после друг друга?

164

Я искал исходный код для nmap, который был выпущен в 1997 году, и заметил этот фрагмент кода, который выглядит немного странным для меня:

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

Зачем тебе i++;и то i--;сразу после друг друга? iесть 0, то i++превращается iв 1. После этого i--превращается iв 0.

Ссылка на оригинальный исходный код. Ищи:

i++;
i--;

Кто-нибудь может объяснить, для чего это?

DDiamond
источник
25
Спросите автора .
Даблер
8
Я предполагаю, что они были частью некоторого экспериментального или отладочного кода, который автор впоследствии забыл удалить.
Нейт Элдридж
6
Причина, очевидно, состоит в том, чтобы сбить вас с толку, это единственная цель :-) Есть небольшая вероятность, что это работает из-за некоторой ошибки компилятора в каком-то древнем компиляторе, в этом случае должен был быть комментарий, сообщающий нам эту причину.
gnasher729
18
@ RingØ: для забавы я попробовал это с gcc 1.27, около 1988 года, на godbolt: godbolt.org/z/yYyFrQ . (Он не работает с современными системными заголовками, поэтому мне пришлось объявить все стандартные функции библиотеки самостоятельно.) Но с -Oэтим действительно оптимизируются эти операторы.
Нейт Элдридж
21
Это означает, что программист получил оплату по линии ...
TonyK

Ответы:

152

Это была ошибка. Эти строки вместе iостаются неизменными, поэтому их не должно было быть.

Связанная статья, которая представила nmap, была опубликована 1 сентября 1997 года. Если вы посмотрите SVN-репозиторий для nmap по адресу https://svn.nmap.org/nmap , то первоначальная версия, проверенная 10 февраля 1998 года, не имеет таких строк:

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

Так что это то, что автор нашел и исправил между публикацией исходного исходного кода nmap и начальной регистрацией в SVN.

dbush
источник
1
Хм, на этой странице <pre>тоже нет тегов вокруг статьи; Инспектор Chrome показывает, как это приводит к искажению документов во время создания DOM;)
Астероиды с крыльями
4
Это смущает читателей, что совершенно непреднамеренно. Я бы сказал, что это явно ошибка. ;-)
сержут
2
@sergut Википедия не согласна с вами, но это сообщение в блоге , и я тоже склонен :-)
Тойво Савен
4
Теперь, если бы iне int, а какой-то причудливый класс с перегрузками операторов, возможно (хотя это маловероятно и, как правило, признак плохой практики кодирования), что это может иметь некоторые побочные эффекты. (Применимо, только если это был C ++, конечно.)
Даррел Хоффман
5
Возможно, стоит отметить, что в некоторых контекстах (отображение ввода-вывода в памяти) изменение переменной может иметь внешние последствия.
nullromo
40

Это бесполезно. Это абсолютно ничего не делает.

Если бы я предположил, что это, вероятно, остатки некоторого кода отладки, который использовался во время разработки.

Я предполагаю, что либо один из i++илиi-- было введено в одном изменении, а другое - в другом.

Однако у меня нет возможности найти точку введения, поскольку между первоначальным исходным выпуском и первой ревизией SVN не было истории изменений.

СС Энн
источник
14
Я думаю, что предположение об отладке кода является точным. Я видел так много разных видов кода для отладки, чтобы получить точки останова там, где вы ожидаете их.
Натан Гоингс
9

Для неоптимизирующего компилятора или компилятора, распознающего побочные эффекты оборудования, i ++; i-- последовательность приведет к тому, что i будет считываться из памяти, а затем перезаписываться независимо от пути, пройденного через цикл for и вложенного в if.

При параллельной обработке иногда используются взломы компилятора, чтобы гарантировать, что последовательность кода использует свои собственные локальные копии переменных, а не глобальные копии.

Поскольку пример представляет собой фрагмент кода, нельзя определить используемый компилятор, ожидаемую операционную систему / аппаратное обеспечение, а также то, находится ли это в последовательности / функции кода, которую можно выполнить как независимый поток.

В более простых системах я временно вынудил изменения переменных использовать функцию прерывания в среде отладки. Если бы это было так, автор, возможно, забыл удалить код, когда разработка была завершена.

Ларри Фишер
источник
1
тогда почему бы просто не объявить это как изменчивое?
вс
6
Объявление iв качестве локальной переменной показано в приведенном выше коде, и нет другого способа получить доступ к нему из другого потока в той точке, где i++; i--находятся строки.
междурядный
@ vsz Я скорее думаю, что он имеет в виду iбыть вынужденным быть энергонезависимым. Я не имел дело с многопоточностью в C или C ++, поэтому я понятия не имею, как это можно трактовать как изменчивое и как i++; i--это подавить.
Егор Ганс
У volatile есть и другие цели, кроме безопасности потоков. Его также можно использовать при отладке, чтобы компилятор не оптимизировал его.
вс
2

Я предлагаю вам проверить только обновленный код. Если вы используете (i = 2 + 1) сразу после этого (i-1), это не имеет смысла. Значение i остается неизменным. Вы можете попробовать это, используя любой компилятор c или c ++. или даже на любом другом языке это то же самое. Запустите код в компиляторе, чтобы увидеть, ошибаюсь я или нет, и дайте мне знать, если я даю неправильный ответ.

TripleM
источник