Що робить розробників C настільки цікавими, якщо “i ++ == ++ i”? [зачинено]


15

Просто випадкове спостереження, здається, що на StackOverflow.com виникають питання про те, якщо "++ i == i ++". Це питання постійно задають, хоча, я думаю, я бачив, що його задавали приблизно 6 або 7 разів за останні 2 місяці.

Мені просто цікаво, чому розробники C так зацікавлені в ньому? Таке ж поняття / питання існує і для C # та Java розробників, але я думаю, що я бачив лише одне питання, пов'язане з C #.

Це тому, що так багато прикладів використовують ++ i? Це тому, що є якась популярна книга чи підручник? Це тому, що розробники C просто люблять якомога більше втиснутись в єдиний рядок для "ефективності" / "продуктивності" і тому частіше зустрічають "дивні" конструкції, використовуючи оператор ++?


23
(Для мене як C # dev, i ++ і ++ я рівні. Я знаю, що це не так, але якщо я напишу код, який залежить від різниці, я скоріше перероблюю його, щоб він був більш читабельним, і очікую, що компілятор та JITter подбають з цього приводу, але як C # dev я не намагаюсь зберегти один або два цикли годин, тому що я вже відносно неефективний)
Michael Stum

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

2
Ви буквально маєте на увазі вираз ++i == i++, або взагалі про різницю в значенні між ++iі i++?
Кіт Томпсон

Відповіді:


30

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

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


14
Хіба це не протилежність Вічного вересня? Вічний вересень був тоді, коли AOL почав пропонувати Usenet доступ своїм клієнтам, і це виглядало як вересень (місяць, коли нові учні, які починають школу, традиційно обстрілювали дошки як новачків) цілий рік.
nlawalker

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

12

Тому що програмісти C МОЖУТЬ зрозуміти порядок операцій. Розробники C # не обов'язково використовують побітові оператори (&, |, ~) або префіксні оператори, оскільки ми зазвичай більше турбуємось про інші речі. Однак те, що ми C # devs не усвідомлюємо, - це те, що ми повинні знати, що роблять оператори, якими ми користуємося щодня та як правильно ними користуватися. Більшість із нас просто уникають місць, де це може бути проблемою.

Який вихід цього фрагмента у верхній частині вашої голови?

    double x = 5.5;
    Console.WriteLine(x++);
    x = 5.5;
    Console.WriteLine(++x);

Я б сказав, що гарна кількість досвідчених C # devs не має уявлення про те, який вихід на консоль.


3
+1. Знати різницю між операторами збільшення та зменшення до і після виправлення варто для таких ситуацій.
Малрус

4
Я якось бачу сенс, і вихід не знаю (я вважаю, що це 5,5 і 6,5, але я не впевнений), і для мене це не має значення, оскільки я б переробляв його на x ++; Console.WriteLine (x); негайно. Я не зовсім неосвічений, але просто думаю, що це великий запах коду з нульовою зручністю використання.
Майкл Стум

9
Відповідь на питання не має нічого спільного з порядком операцій або різницею між прирістками префікса та постфікса. Це питання визначеної та невизначеної поведінки.
Девід Торнлі

2
Я зіткнувся з цим сьогодні. Щось подібне if (myList[i++] == item). Розумний. Я виявив, що шукає джерело винятку IndexOutOfRange ... Дійсно, дуже "розумний".
rmac

7
Я думаю, що це 5,5 і 6,5, але я ніколи не бачив, щоб він ++використовувався на поплавці, і мушу сказати, що це не дуже доречно. Люди роблять це? (Я вважаю за краще += 1)
Барт ван Хекелом

8

Я думаю, що це очевидно. У C #, для int i, i++ == ++iзавжди помилково , а ++i == i++це завжди вірно, надійно, і все , хто зацікавлений може знайти це легко , просто навчання правилам C # (або на самому ділі, просто запустивши його).

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


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

+1: Це насправді відповідає на поставлене запитання (тобто ви не читаєте між рядків).
Томас Едінг

7

Це популярне запитання, оскільки це хитрість. Це не визначено .

Посилання, наведене вище, переходить до поширених запитань на домашній сторінці Bjarnes Stroustrup, де конкретно розглядається це питання та пояснюється, чому ця конструкція не визначена. Що там сказано:

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

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


5

Найімовірніше, тому що в C це дійсно має значення, якщо ви пишете i++або ++iколи ви робите арифметику вказівника. Там збільшення iдо або після операції може бути вирішальним. Я надам вам приклад, але востаннє, коли я писав С, було 10 років тому ...

У C # я ніколи не стикався з ситуацією, яка вимагає від мене думки i++або ++iтому, що AFAIK для циклів for / while це насправді не має значення.


3
все ще важливо зрозуміти відмінності в C # - тільки тому, що ви, здається, використовуєте їх лише для / кожної петлі, не означає, що це єдине місце, де ви їх знайдете
STW

цілком вірно, що.
Младен Прайдич

3
Це не стосується питання. Питання полягає не в різниці між i++і ++i, а в поєднанні їх в одному виразі.
Девід Торнлі

@David Питання в тому, чому програмістам C це цікаво. Відповідь (Це важливо в C, не стільки в C #) цілком актуальна ".
Флоріан F

2

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

Зараз це тому, що деякі кручені люди пишуть петлі типу

while( [something] )
{
  a[++j] = ++j;
}

Навіть зараз я не надто впевнений у тому, що буде / має статися, але мені цілком зрозуміло, що множина ++ [var] на одній лінії вимагає неприємностей.


2
Зростання мають невизначену поведінку як частину завдання в C
tzenes

7
Призначення на зразок x = ++j;чітко визначені в C. Наведене вище не визначено, оскільки jзмінюється двічі без втручання точок послідовності.
Меттью Флашен

2

Дві причини.

Правильна реалізація ++ i - збільшити i потім повернути його. Правильна реалізація i ++ полягає у збереженні поточного значення, збільшення i та поверненні збереженого значення. Знаючи, що вони не реалізуються, оскільки синоніми важливі.

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

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

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

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

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


5
Основні тести на це будуть вводити в оману, оскільки це невизначена поведінка. Якщо це буде працювати точно так, як ви цього разу очікували, немає гарантії, що це буде наступного разу.
Девід Торнлі

Ви відповіли неправильно. Вам слід відповісти, чому програмісти C цікавляться цим.
Гюго

Ваш другий параметр так чи інакше є невірним (щонайменше до C ++ 11): поведінка ++iполягає у використанні значенняi+1 та в якийсь момент часу, можливо, до цього або після нього, але перед наступним збільшенням пункту послідовностіi .
ММ

@MattMcNabb - Чи можете ви вказати мені специфікацію для цього, мені було б цікаво дізнатись, чи змінилися зміни в реалізації. Ще в ті часи, коли C гарно відображав збірку PDP, ++ я вводив інструкцію INC, тоді як версія суфіксу повинна була скопіювати значення в реєстр для використання інструкції після збільшення. Що становило необхідність описаних вами змін?
Уолт Стоунбернер

2

Я думаю, це річ з культурного шоку.

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

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


Це таким чином, оскільки він був розроблений для підтримки набагато більшої кількості платформ, ніж навіть тоді, коли було визначено C #, включаючи найдивніші вбудовані або основні платформи, про які ви можете придумати. C #, з іншого боку, працює на ... x86 і 360? можливо ARM теж? Більш нічого. Ось чому C # може визначити набагато більше.
DeadMG

++ Крім того, не був C спочатку побудований на PDP-11? Де були вказівки щодо автоматичного збільшення? C хотів бути "близько до машини", щоб він міг корисно використовувати набір інструкцій.
Майк Данлаве

@MikeDunlavey: Ні, C - х ++і --оператори не були засновані на PDP-11, які не існували , коли ці оператори були введені в мові попередника B. Див C в cm.bell-labs.com/who/dmr/chist.html і пошук "автоматичного збільшення".
Кіт Томпсон

1

Можливо, це просто те, що розробники C використовують ++ нарощення частіше загалом - бачачи, як C не має "передбачення" чи подібного твердження до ітерації через масиви. О, і звичайно арифметичний вказівник, як згадувалося раніше!


1
Добре, що забув, що передбачення - це відносно сучасна концепція.
Майкл Стум

-1

Різниця між обома частинами: посада та попередня робота працюють так, як ці дві частини коду повинні функціонувати на кожній мові. ЦЕ НЕ БУДЬ ЗАЛЕЗНИК МОВИ !!!

++i

Це попередній приріст. Цей фрагмент коду спочатку збільшить значення до того, iяк він надішле значення до рядка, де він використовується.

i++

Це приріст посади. Цей фрагмент коду поверне значення до того, iяк воно збільшить значення iв рядку, де він використовується.

В іншому невеликому прикладі:

int main(void)
{
  int i = 0; 
  int result; 
  result = 10 + ++i; 
  printf("%d \n", result); // = 11 

  int j = 0; 
  result = 10 + j++; 
  printf("%d \n", result);// = 10
  return 0;
}

Цей код збирається з результатами на кодовій панелі.

Це пов'язано з внутрішньою реалізацією перевантаження оператора.

++i збільшує значення безпосередньо (і тому трохи швидше)

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

Сподіваюсь, це зараз зрозуміло.


Але це не стосується актуального питання: чому розробники C запитують про це більше, ніж інші. ОП розуміє операторів.
Martijn Pieters

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