Чому я ++; я--; відразу один за одним?


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

Хтось може пояснити, що це за?


25
Запитайте автора .
DaBler

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.


1
Хм, на цій сторінці відсутні також <pre>теги навколо статті; Інспектор Chrome розкриває, як це призводить до того, що якийсь документ перемішується під час будівництва DOM;)
Астероїди з крилами

4
Це бентежить читачів, що зовсім ненавмисно. Я б сказав, що це явно помилка. ;-)
сергут

2
@sergut Вікіпедія не погоджується з вами, але це повідомлення в блозі , і я також схильний :-)
Toivo Säwén

4
Тепер, якщо це iбув не інт, а якийсь фантазійний клас із перевантаженнями оператора, можливо (хоча це малоймовірно і взагалі є ознакою поганої практики кодування), що це може мати деякі побічні ефекти. (Застосовується лише, якщо це, звичайно, C ++.)
Даррел Гофман,

5
Можливо, варто відзначити, що в деяких контекстах (IO-карта IO) зміна змінної може мати зовнішні ефекти.
nullromo

40

Це марно. Це абсолютно нічого не робить.

Якби я міркував, це, ймовірно, залишки коду налагодження, який використовувався під час розробки.

Я здогадуюсь, що або один, i++або i--введений в одній зміні, а інший був введений в іншій.

Я не маю можливості знайти точку введення, оскільки не було історії перегляду між початковим випуском джерела та першою редакцією SVN.


14
Я думаю, що спекуляція щодо налагодження коду є точною. Я бачив так багато різного роду налагоджувального коду просто для отримання точок перерви там, де ви їх очікуєте.
Натан іде

9

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

При паралельній обробці іноді приймаються хаки компілятора, щоб переконатися, що кодова послідовність використовує власні локальні копії змінних, а не глобальні копії.

Оскільки приклад - фрагмент коду, не можна визначити використовуваний компілятор, очікувану операційну систему / апаратне забезпечення, а також чи є це в послідовності / функції коду, яку можна виконати як незалежний потік.

У більш простих системах я тимчасово примушував змінювати змінні, щоб здійснювати функцію пастки в середовищі налагодження. Якби це було так, автор, можливо, забув видалити код після завершення розробки.


1
то чому б просто не оголосити це мінливим?
vsz

6
Оголошення iяк локальної змінної показано в наведеному вище коді, і немає жодного способу отримати доступ до цього іншого потоку в точці, де розташовані i++; i--рядки.
interjay

@vsz Я вважаю, що він означає, що iвін змушений бути енергонезалежним. Я не займався нанизуванням на C або C ++, тому не маю поняття, як це можна трактувати як мінливий і як i++; i--це придушити.
Єгор Ганс

Леткий має інші цілі, крім безпеки різьби. Його також можна використовувати під час налагодження, щоб переконатися, що компілятор не оптимізує його.
vsz

2

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.