Чи є технічна причина використовувати> (<) замість! = При збільшенні на 1 у циклі 'для'?


198

Я майже ніколи не бачу такого forциклу:

for (int i = 0; 5 != i; ++i)
{}

Чи є технічна причина використовувати >або <замість цього !=приріст на 1 у forциклі? Або це більше конвенція?


104
Це робить його більш читабельною, плюс якщо ви коли-небудь перейдете i++на i+=2(наприклад), вона працюватиме дуже довго (або, можливо, назавжди). Тепер, оскільки ви зазвичай використовуєте <для тих випадків, коли ви збільшуєте ітератор більше ніж на 1, ви також можете використовувати його <і для випадку, коли ви збільшуєте його на 1 (для послідовності).
barak manos

112
5 != iє зло
Слава

27
Ви завжди повинні бути в курсі того, що робите, але все одно будете робити помилки. Використання <зменшує можливість когось ввести помилку в цей код.
Aurast

40
@OleTange Якщо ви повторюєте, використовуючи цифри з плаваючою комою, ви вже накрутили ..
CaptainCodeman

29
@Slava ... не зла. Ви, мабуть, ніколи не кусалися в С простим друком, роблячи різницю між if ( i == 5 ) ...і if ( i = 5 ). Дуже різні речі. Повернення операндів запобігає проблемі: оскільки літералів немає lvals, їх не можна призначити, і компілятор кидається на друкарський помилок. @Zingam: гарне оборонне програмування!
Ніколас Кері

Відповіді:


303
while (time != 6:30pm) {
    Work();
}

Це 6:31 вечора ... Чорт, зараз наступний мій шанс повернутися додому завтра! :)

Це свідчить про те, що більш сильне обмеження зменшує ризики і, ймовірно, більш інтуїтивно зрозуміло.


25
Іноді спроба "пом'якшити ризики" просто закінчується приховуванням помилки. Якщо конструкція циклу повинна перешкоджати проскоченню непомітно 18:30 вечора, то використання <приховає помилку, але використання !=дозволить зрозуміти, що існує проблема.
Адріан Маккарті

27
@AdrianMcCarthy: Не обов'язково; він може просто ввести другу помилку, роблячи діагноз складніше .
Гонки легкості по орбіті

4
@AdrianMcCarthy: Ось такий мій погляд; у вас може бути кілька примірників цього, яких ви ще не бачили;)
Гонки легкості в орбіті

6
Ітератори - це прекрасний приклад точки @AdrianMcCarthy, я думаю. Рекомендований для них порівняння! = Замість <.
Taekahn

5
Я бачив саме цю помилку (і це спричинило 3 місяці налагодження) - але ця відповідь цілком пропускає суть. У наведеному прикладі неможливо пропустити умову кінця. Можна навіть сказати, що свідомо обирати! = Понад <- це твердо стверджувати цей факт. Пом'якшення ризику, який остаточно не існує, для мене викликає кодовий запах. (Сказавши це, ви можете в рівній мірі стверджувати, що <ідіоматично, що це настільки ж хороший привід використовувати його як будь-який.)
Ian Goldby

95

Технічної причини немає. Але є пом’якшення ризику, ремонтопридатності та кращого розуміння коду.

<або >є більш сильними обмеженнями, ніж!= у більшості випадків і відповідають точно такій самій цілі (я б навіть сказав у всіх практичних випадках).

Існує дублікат питання тут ; і одна цікава відповідь .


6
Є деякі типи, наприклад, ітератори, які не підтримують <або>, але підтримують == і! =.
Саймон Б

1
Це цикл for з int . Немає ітераторів.
Елі

7
"Але є пом’якшення ризику, ремонтопридатності та кращого розуміння коду". Все це, власне, технічні причини. :-)
TJ Crowder

@TJCrowder Що це за причина, коли ви просто хочете поговорити про те, що робитимуть машини в результаті?
Brilliand

1
@DanSheppard Я, як правило, вважаю, що зменшення ризику та збереження придатності є діловими причинами, а краще розуміння коду - соціальною причиною (хоча ці причини в цьому випадку застосовуються до технічного питання). Міркування щодо "зменшення ризику" жодним чином не обмежуються технічними питаннями, а міркування "кращого розуміння коду" можуть змінитися, якщо ви виявите, що працюєте з іншою групою людей (навіть якщо задіяні машини взагалі не змінюються. ).
Brilliand

85

Так, є причина. Якщо ви пишете (звичайний старий індекс) для циклу, як це

for (int i = a; i < b; ++i){}

тоді він працює як очікується для будь-яких значень aта b(тобто нульових ітерацій, коли a > bзамість нескінченного, якщо ви використовувалиi == b; ).

З іншого боку, для ітераторів ви писали б

for (auto it = begin; it != end; ++it) 

тому що будь-який ітератор повинен реалізувати operator!=, але не для кожного ітератора можна надати йогоoperator< .

Також на основі діапазону для петель

for (auto e : v)

- це не просто фантазійний цукор, але вони помірно знижують шанси написати неправильний код.


4
Гарний приклад. Мене зацікавить випадок !=замість <. Я особисто ніколи не використовував те, що я думаю.
Елі

@Elyasin Я не знайшов хорошого, і я не хотів опублікувати поганий: Уявіть, у вас є якийсь круговий контейнер, де ви збільшуєте на + x модуль розмір контейнера N і ви хочете зупинити цикл, коли ви досягти певного показника .... ну це справді поганий приклад. Можливо, я знайду кращого
idclev 463035818

Той самий цикл з! = Замість <дає зрозуміти, яка перевага <(або>) в цьому контексті. for (int i=a; i != b; i++) {}
Пол Сміт

10
Використовувати що-небудь крім !=ітераторів досить небезпечно, тому що іноді ітератори можуть бути меншими порівняно (наприклад, вказівник), але порівняння безглуздо (це пов'язаний список).
Zan Lynx

1
Навчіться серйозно використовувати білий простір.
Майлз Рут

70

Ви можете мати щось подібне

for(int i = 0; i<5; ++i){
    ...
    if(...) i++;
    ...
}

Якщо ваша змінна циклічна запис записана внутрішнім кодом, ця i!=5петля може не порушити. Це безпечніше перевірити на нерівність.

Редагувати щодо читабельності. Форма нерівності набагато частіше використовується. Тому це дуже швидко читати, оскільки нічого особливого для розуміння (навантаження на мозок зменшується, оскільки завдання є загальним). Тому читачам це здорово використовувати ці звички.


6
Цей тип внутрішнього "if (умова), то я ++" - це перше, що я подумав.
WernerCD

3
Очікував, що це буде найвища відповідь; Я був здивований, що мені довелося прокрутити цю відстань, щоб знайти її. Це робить набагато більше, щоб переконати початківця програміста, ніж "ну, ви повинні використовувати найсильнішу умову". Інші відповіді, якщо вони залишаться на вершині, повинні містити це як чітке і очевидне пояснення того, що може піти не так у запропонованому кодом ОП.
msouth

1
@msouth Я повністю згоден, але моя POV досить суб’єктивна;)
johan d

3
@msouth Мені подобається, коли несподівана виробнича поведінка викриває мої помилки, чи не так? :-)
deworde

3
@msouth Подивіться, все, що нам потрібно зробити, це ніколи не робити жодних помилок і все буде добре. Симплекс.
deworde

48

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

Єдиний випадок, коли оборонне програмування не потрібно - це стан, який було доведено до і після умов (але потім, доведення цього є найбільш захисним з усіх програмувань).


2
Хороший приклад на підтвердження цього: пам'ять вразлива до бітових фліп ( SEU ), викликаних радіацією. При використанні intдля i != 15умови, то лічильник буде працювати в протягом тривалого часу , якщо що - або вище четвертого біта перевертається, особливо на машинах , де sizeof(int)64. Seus є дуже реальною проблемою на велику висоту або в просторі (з - за більш високу радіацію) або у великих суперкомп'ютерах (бо стільки пам’яті).
Джош Санфорд

2
Думаючи, що ваша програма буде працювати нормально, коли радіація змінює вашу пам'ять - це оптимістичний спосіб і антикатастрофічний спосіб мислення ... хороший коментар! :)
Луїс Колорадо

37

Я б стверджував, що вираз, як

for ( int i = 0 ; i < 100 ; ++i )
{
  ...
}

більш виразне намір , ніж

for ( int i = 0 ; i != 100 ; ++i )
{
  ...
}

Перший чітко зазначає, що умова є тестом для ексклюзивної верхньої межі діапазону; останнє є бінарним тестом умови виходу. І якщо тіло циклу нетривіальне, може бути не видно, що індекс модифікується лише в самому forтвердженні.


13
"Я хочу, щоб ця петля працювала не більше 5 разів" проти "Я хочу запустити цю петлю стільки разів, скільки потрібно, за винятком рівно 5 разів, чого я не хочу".
єпископ

+1 для згадування верхньої межі діапазону. Я думаю, що це важливо для числових діапазонів. ! = не визначає належний діапазон у циклі for для такого типу
element11

22

Ітератори є важливим випадком, коли ви найчастіше використовуєте !=позначення:

for(auto it = vector.begin(); it != vector.end(); ++it) {
 // do stuff
}

Звісно: на практиці я б написав те саме, спираючись на range-for:

for(auto & item : vector) {
 // do stuff
}

але справа залишається: звичайно можна порівнювати ітератори за допомогою ==або !=.


2
Ітератори часто мають лише поняття рівності / нерівності, а не впорядкування, ось чому ви їх використовуєте !=. Наприклад, у a, який std::vectorви можете використовувати <як ітератор, прив’язаний до індексу / вказівника, але в a std::setнемає такого строгого впорядкування, оскільки він ходить по бінарному дереву.
Мартін К.

19

Умова циклу є інваріантним циклом.

Припустимо, ви не дивитесь на тіло петлі:

for (int i = 0; i != 5; ++i)
{
  // ?
}

в цьому випадку ви знаєте на початку ітерації циклу, iяка не дорівнює 5.

for (int i = 0; i < 5; ++i)
{
  // ?
}

у цьому випадку ви знаєте на початку ітерації циклу, яка iменша за5 .

Друга - це набагато, набагато більше інформації, ніж перша, ні? Тепер намір програміста (майже напевно) той самий, але якщо ви шукаєте помилок, мати впевненість у читанні рядка коду - це добре. А друга примушує цю інваріантну, а це означає, що деякі помилки, які б укусили вас у першому випадку, просто не можуть відбутися (або не спричинити пошкодження пам’яті, скажімо) у другому випадку.

Ви знаєте більше про стан програми, з читання менше коду, з, <ніж з !=. А на сучасних процесорах вони займають стільки ж часу, скільки немає різниці.

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

Деякі з цих фактів відносно прості, але ви можете помилитися. Перевірка всього корпусу петлі - це, однак, біль.

В C ++ ви можете написати такий indexesтип, що:

for( const int i : indexes(0, 5) )
{
  // ?
}

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

Чим більше інформації ви можете отримати з рядка коду, не розуміючи контексту, тим простіше відстежити, що йде не так. <у випадку цілих циклів дає більше інформації про стан коду в цьому рядку, ніж !=це робить.



13

Може статися, що змінна iвстановлена ​​на якесь велике значення, і якщо ви просто використовуєте !=оператор, ви опинитеся в нескінченному циклі.


1
Не дуже нескінченна - у більшості реалізацій C, iмовчки загортається, коли на максимумі. Але так, швидше за все довше, ніж ви готові чекати.
usr2564301

12

Як видно з інших численних відповідей, є причини використовувати <замість! =, Що допоможе у кращих випадках, початкових умовах, ненавмисній модифікації лічильника циклу тощо.

Чесно кажучи, я не думаю, що ти можеш достатньо наголосити на важливості конвенції. У цьому прикладі іншим програмістам буде досить легко бачити, що ви намагаєтеся зробити, але це спричинить подвійний результат. Одне із завдань під час програмування - це зробити його максимально зрозумілим та знайомим всім, тому неминуче, коли комусь доведеться оновити / змінити ваш код, це не потребує великих зусиль, щоб з'ясувати, що ви робили в різних блоках коду . Якби я бачив, як хтось використовує !=, я б припустив, що є причина, що вони використовували його замість, <і якби це був великий цикл, я переглянув би все це, намагаючись зрозуміти, що ти зробив, що зробило це необхідним ... і це витрачений час.


12

Як уже сказав Ієн Ньюсон, ви не можете надійно переосмислити плаваючу змінну і вийти за допомогою !=. Наприклад,

for (double x=0; x!=1; x+=0.1) {}

насправді буде циклічно назавжди, тому що 0,1 не може бути точно представлений у плаваючій точці, отже лічильник вузько пропускає 1. С < ним припиняється.

(Однак зауважте, що це в основному невизначена поведінка, незалежно від того, отримаєте ви 0,9999 ... як останнє прийняте число - яке порушує менше, ніж припущення, - або вже виїжджаєте на 1.0000000000000001.)


10

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

З цією метою відповідь: ні (*). (*) - "перегляньте посібник з процесора". Якщо ви працюєте з якоюсь кращою системою RISC або FPGA, можливо, вам доведеться перевірити, які інструкції генеруються і які коштують. Але якщо ви використовуєте досить багато будь-яку звичайну сучасну архітектуру, то немає суттєвої різниці рівня процесора в вартості між lt, eq, neі gt.

Якщо ви використовуєте крайній випадок ви можете виявити , що !=потрібно три операції ( cmp, not, beq) проти двох ( cmp,blt xtr myo ). Знову ж таки, RTM у цьому випадку.

Здебільшого причини - захисні / загартовувальні, особливо при роботі з покажчиками або складними петлями. Розглянемо

// highly contrived example
size_t count_chars(char c, const char* str, size_t len) {
    size_t count = 0;
    bool quoted = false;
    const char* p = str;
    while (p != str + len) {
        if (*p == '"') {
            quote = !quote;
            ++p;
        }
        if (*(p++) == c && !quoted)
            ++count;
    }
    return count;
}

Менш надуманим прикладом може бути те, коли ви використовуєте зворотні значення для виконання приростів, приймаючи дані від користувача:

#include <iostream>
int main() {
    size_t len = 5, step;
    for (size_t i = 0; i != len; ) {
        std::cout << "i = " << i << ", step? " << std::flush;

        std::cin >> step;
        i += step; // here for emphasis, it could go in the for(;;)
    }
}

Спробуйте це і введіть значення 1, 2, 10, 999.

Ви можете запобігти цьому:

#include <iostream>
int main() {
    size_t len = 5, step;
    for (size_t i = 0; i != len; ) {
        std::cout << "i = " << i << ", step? " << std::flush;
        std::cin >> step;
        if (step + i > len)
            std::cout << "too much.\n";
        else
            i += step;
    }
}

Але те, що ви, мабуть, хотіли

#include <iostream>
int main() {
    size_t len = 5, step;
    for (size_t i = 0; i < len; ) {
        std::cout << "i = " << i << ", step? " << std::flush;
        std::cin >> step;
        i += step;
    }
}

Існує також щось упереджене до конвенції <, оскільки замовлення в стандартних контейнерах часто покладається на operator<, наприклад, хешування в декількох контейнерах STL визначає рівність, кажучи

if (lhs < rhs) // T.operator <
    lessthan
else if (rhs < lhs) // T.operator < again
    greaterthan
else
    equal

Якщо lhsі rhsє визначений користувачем клас, пише цей код як

if (lhs < rhs) // requires T.operator<
    lessthan
else if (lhs > rhs) // requires T.operator>
    greaterthan
else
    equal

Виконавець повинен передбачити дві функції порівняння. Так <став прихильним оператором.


Для читабельності i + = крок повинен бути у контрольній частині. У випадку, якщо ви зробите крок = 0
Mikkel Christiansen

1
Хоча це допоможе читати хороший код, я хотів підкреслити недолік у помилковій версії
kfsone

9

Існує кілька способів написання коду будь-якого типу (як правило), у цьому випадку просто буває два способи (три, якщо порахувати <= і> =).

У цьому випадку люди віддають перевагу> і <, щоб переконатися, що навіть якщо у циклі трапиться щось несподіване (наприклад, помилка), воно не зациклюється нескінченно (BAD). Розглянемо, наприклад, наступний код.

for (int i = 1; i != 3; i++) {
    //More Code
    i = 5; //OOPS! MISTAKE!
    //More Code
}

Якби ми використовували (i <3), ми б були в безпеці від нескінченного циклу, оскільки це поставило більше обмеження.

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

Сподіваюся, це допомогло!


можна аргументувати, що нескінченний цикл буде хорошим показником помилки, але тоді інший стверджує, що i = 5 не обов'язково є помилкою
njzk2

7

Найпоширеніша причина використання <- це конвенція. Більшість програмістів вважають петлі на кшталт цього «поки індекс знаходиться в діапазоні», а не «поки індекс не досягне кінця». Там цінність дотримується умовності, коли можна.

З іншого боку, багато відповідей тут стверджують, що використання <форми допомагає уникнути помилок. Я б заперечував, що у багатьох випадках це просто допомагає приховати помилки. Якщо індекс циклу повинен досягати кінцевого значення, а натомість він фактично виходить за його межі, то трапляється щось, чого ви не очікували, що може спричинити несправність (або бути побічним ефектом чергової помилки). <, Ймовірно , затримає відкриття помилки. !=, Швидше за все, призведе до кабінки, зависання або навіть аварії, яка допоможе вам знайти помилку раніше. Чим раніше буде виявлена ​​помилка, тим дешевше її виправити.

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

Наприклад, якщо ви переходите через звичайний рядок C, зазвичай пишемо:

for (char *p = foo; *p != '\0'; ++p) {
  // do something with *p
}

ніж

int length = strlen(foo);
for (int i = 0; i < length; ++i) {
  // do something with foo[i]
}

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

За допомогою рядка C ++ std :: ви використовуєте діапазон для циклу, стандартного алгоритму чи ітераторів, навіть якщо довжина легко доступна. Якщо ви використовуєте ітератори, умовою є використання, !=а не <як:

for (auto it = foo.begin(); it != foo.end(); ++it) { ... }

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


3
Ви цілком правильно підкреслили важливість ідіоми в програмуванні. Якщо я дивлюсь на якийсь код і він має звичний зразок, мені не потрібно витрачати час на виведення шаблону, але я можу перейти прямо до його суті. Я думаю, що це моя основна боротьба з порівняннями Yoda - вони не виглядають ідіоматичними, тому я нарешті повинен прочитати їх двічі, щоб бути впевненим, що вони означають те, що я думаю, що вони означають.
Toby Speight

7

Однією з причин не використовувати цю конструкцію є числа з плаваючою комою. !=це дуже небезпечне порівняння для використання з поплавками, оскільки воно рідко оцінить справжнє, навіть якщо цифри виглядають однаково. <або >знімає цей ризик.


Якщо ваш ітератор циклу - це число з плаваючою комою, то !=порівняно <- це найменше з ваших проблем.
Лундін

7

Існує дві пов'язані з цим причини цієї практики, що обидві стосуються того, що мова програмування - це врешті-решт мова, яку читатимуть люди (серед інших).

(1) Трохи надмірності. На природній мові ми зазвичай надаємо більше інформації, ніж це суворо необхідно, як і виправлення помилок. Тут додаткова інформація полягає в тому, що змінна петля i(див. Як я тут використовував надмірність? Якщо ви не знали, що означає "змінна петля", або якщо ви забули ім'я змінної, прочитавши "змінну циклу i", ви отримаєте повну інформація) менше, ніж 5 протягом циклу, не просто відрізняється від 5. Надмірність підвищує читабельність.

(2) Конвенція. Мови мають специфічні стандартні способи вираження певних ситуацій. Якщо ви не будете дотримуватися встановленого способу сказати щось, ви все одно зрозумієте, але зусилля для одержувача вашого повідомлення більше, оскільки певні оптимізації не спрацюють. Приклад:

Не розмовляйте навколо гарячої кашки. Просто висвітліть труднощі!

Перше речення - це дослівний переклад німецької ідіоми. Друга - це загальна англійська ідіома з основними словами, заміненими синонімами. Результат зрозумілий, але для розуміння цього потрібно набагато більше часу:

Не бийте навколо куща. Просто поясніть проблему!

Це справедливо навіть у тому випадку, якщо синоніми, які використовуються в першій версії, трапляються краще, ніж звичайні слова в англійській ідіомі. Подібні сили діють, коли програмісти читають код. Ось чому це 5 != iі 5 > iє дивні способи його розміщення, якщо ви не працюєте в середовищі, в якому звичайно проводити обмін на більш нормальне i != 5та i < 5таким чином. Такі діалектні спільноти існують, ймовірно, тому, що послідовність полегшує запам’ятовування писати 5 == iзамість природного, але схильного до помилок i == 5.


1
Ausgezeichnet . Так само не можна було б записати тест як i < 17+(36/-3)(навіть коли це константи, які використовуються в іншому місці; тоді для чіткості слід записати їх назви !).
usr2564301

6

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

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

Іншим прикладом, який демонструє більш широку застосовність порівняння рівності в таких контекстах, є популярна головоломка з реалізацією unsignedітерації аж до 0. Це можна зробити як

for (unsigned i = 42; i != -1; --i)
  ...

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


2

Окрім прикладів, коли змінна циклічність (ненавмисно) зміниться всередині тіла, є й інші міркування щодо використання операторів менших чи більших розмірів, ніж операторів:

  • Заперечення ускладнюють розуміння коду
  • <або >є лише один, але !=два

4
Друга куля - у кращому випадку легковажна причина. Код повинен бути правильним і чітким. Компактність набагато менш важлива.
Джонатан Леффлер

@JonathanLeffler Добре, що у відповіді на TDD цей додатковий символ є однією додатковою наносекундою для розбору та разів на мільярд ітерацій, щоб знайти помилку, викликану написанням 5 != $i, що просто зайняло одну цілу секунду мого життя. Ух ... снікер
єпископ

1

На додаток до різних людей, які згадували, що це зменшує ризик, воно також зменшує кількість перевантажень функцій, необхідних для взаємодії з різними стандартними компонентами бібліотеки. Наприклад, якщо ви хочете, щоб ваш тип зберігався в a std::setабо використовувався як ключ для std::mapабо використовувався з деякими алгоритмами пошуку та сортування, стандартна бібліотека зазвичай використовує std::lessдля порівняння об'єктів, оскільки для більшості алгоритмів потрібне лише суворе слабке впорядкування . Таким чином, стає доброю звичкою використовувати <порівняння замість !=порівнянь (де, звичайно, це має сенс).


1
ви можете мати рацію щодо кількості перевантажень, але, розглядаючи вимоги до об'єктів, тоді для майже будь-якого об'єкта можна визначити !=оператора, але не завжди можливо визначити суворе слабке впорядкування. У цьому сенсі !=було б краще, оскільки це ставить менше вимог до типу. Однак я все ще залишаюся з <.
idclev 463035818

0

З точки зору синтаксису проблеми немає, але логіка, що стоїть за цим виразом 5!=i, не є звуком.

На мій погляд, використання !=для встановлення меж циклу for циклу не є логічно здоровим, оскільки для циклу або збільшується, або зменшує індекс ітерації, тому встановлення циклу ітерації, поки індекс ітерації не вийде за межі (!= до чогось) належна реалізація.

Це буде працювати, але воно схильне до неправильної поведінки, оскільки обробка даних про кордони втрачається при використанні !=для додаткової проблеми (це означає, що ви знаєте з самого початку, якщо вона збільшується чи зменшується), ось чому замість !=цього <>>==>використовується.


2
Логіка ідеально чудова. Коли iце 5цикл завершується. Ти мав на увазі сказати щось інше?
Dan Getz

1
Якщо дані не переносяться правильно через тепло, електромагнітні впливи ваш код працює назавжди. Якщо ви робите це на звичайній робочій станції або сервері з оперативною пам’яттю ECC, це не проблема (ні логічна, ні технічна, ні фізична)
Markus
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.