Что делает разработчиков на C таким любопытным, если «i ++ == ++ i»? [закрыто]

15

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

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

Это потому, что многие примеры используют ++ i? Это потому, что есть какая-то популярная книга или учебник? Это потому, что разработчики C просто любят втиснуть как можно больше в одну строку для «эффективности» / «производительности» и поэтому чаще сталкиваются с «странными» конструкциями, использующими оператор ++?

Майкл Стум
источник
23
(Для меня, как для C # dev, i ++ и ++ я равны. Я знаю, что это не так, но если я напишу код, который зависит от разницы, я бы предпочел рефакторинг, чтобы он был более читабельным и ожидал, что компилятор и JITter позаботятся об этом, но как разработчик C # я не пытаюсь сохранить один или два такта, потому что я все равно уже относительно неэффективен)
Майкл Стум
1
как начинающие программисты, мы любим играть с арифметикой, логикой и любопытно, как все работает. Я думаю, что это большая причина, почему мы, новички, любим такие вопросы. это может быть не новаторская функция, но это, безусловно, интересно! разве это не причина, по которой мы стали программистами ?!
Чани
2
Вы буквально ссылаетесь на выражение ++i == i++или, в более общем смысле, на разницу в значении между ++iи i++?
Кит Томпсон

Ответы:

30

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

Таким образом, я думаю, что справедливо предположить, что довольно многие из них являются просто результатом уроков, в которых учитель говорит хотя бы немного об этом, но не очень хорошо объясняет свою точку зрения (так часто, как нет). потому что он на самом деле не понимает их сам). Особенно на основе людей, которые, кажется, задают эти вопросы, немногие основаны на реальном кодировании.

Джерри Гроб
источник
14
Разве это не противоположность Вечного сентября? Вечный сентябрь был, когда AOL начал предлагать Usenet доступ к своим клиентам, что выглядело как сентябрь (месяц, когда новые ученики, начинающие школу, традиционно бомбардируют доски как новички) круглый год.
nlawalker
Это интересная теория, но, возможно, это не всегда вина учителей, если кто-то не понимает материала: возможно, студенты (1) не уделяли достаточного внимания во время урока и (2) ленились искать ответ на stackoverflow перед тем, как задавая тот же вопрос снова.
Джорджио
12

Потому что программисты на С ДОЛЖНЫ понимать порядок операций. Разработчики C # не обязательно используют побитовые операторы (&, |, ~) или префиксные операторы, так как мы обычно больше беспокоимся о других вещах. Однако мы, разработчики C #, не понимаем, что мы должны знать, что делают операторы, которые мы используем ежедневно, и как их правильно использовать. Большинство из нас просто избегают мест, где это может быть проблемой.

Вне головы, каков результат этого фрагмента?

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

Я бы сказал, что многие опытные разработчики C # не имеют ни малейшего представления о том, что выводит консоль.

Нейт Нунен
источник
3
+1. Знание различий между операторами увеличения / уменьшения до и после исправления того стоит.
Maulrus
4
Я как бы вижу смысл, и я не знаю выходных данных (я думаю, что это 5.5 и 6.5, но я не уверен), и для меня это не будет иметь значения, так как я бы реорганизовал его в 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 ++, с другой стороны, он близок к неопределенному, поскольку зависит от компилятора, среды выполнения, платформы и т. Д., Поэтому ответить на этот вопрос гораздо сложнее, поэтому многие задают его.

Timwi
источник
+1 - но это не очень сложный вопрос. «undefined» - это одно слово. Все, что "зависит от ..." - это то, о чем большинство людей не беспокоятся. Даже если вы пишете только для одной конкретной платформы, вы должны использовать обычные идиомы для языка в целом, и большинство применений операторов перед приращением и после приращения являются частью нескольких распространенных идиом.
Steve314
+1: это фактически отвечает на заданный вопрос (то есть вы не читаете между строк).
Томас Эдинг
7

Это популярный вопрос, потому что это вопрос с подвохом. Это не определено .

Ссылка выше ведет к часто задаваемым вопросам на домашней странице Bjarnes Stroustrup, где конкретно рассматривается этот вопрос, и объясняется, почему эта конструкция не определена. Что это говорит:

В основном, в C и C ++, если вы дважды читаете переменную в выражении, где вы также пишете, результат не определен.

Утверждение о том, что порядок оценки не определен, дает более эффективный код.

user16764
источник
5

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

В C # я никогда не сталкивался с ситуацией, которая заставила бы меня задуматься i++или ++iпотому что AFAIK, для циклов for / while, это не имеет большого значения.

Младен Прайдич
источник
3
все еще важно понимать различия в C # - просто потому, что вы, кажется, используете их только в циклах for / each, это не означает, что это единственное место, где вы их найдете
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, ++ i вводил инструкцию INC, тогда как версия суффикса должна была копировать значение в регистр для использования инструкции после приращения. В чем заключалась необходимость описанных вами изменений?
Уолт Стоунбернер
2

Я думаю, что это вещь культурного шока.

Как уже указывалось, поведение выражения в C или C ++ может быть неопределенным, поскольку порядок выполнения постинкрементов и т. Д. Строго не определен. Неопределенное поведение довольно распространено в C, и, конечно, многое из этого было импортировано в C ++.

Кто-то, кто занимался программированием на другом языке, кто-то, кто понял идею, что языки программирования должны быть точными, и что компьютеры должны делать то, что им говорят ... ну, это шок для обнаружить, что C намеренно расплывчат в некоторых вещах.

Steve314
источник
Таким образом, 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 нет «foreach» или подобного оператора для перебора массивов. Ну и конечно же указатель арифметический, как уже упоминалось ранее!

Роберт Роос
источник
1
Хорошая мысль, забыл, что foreach - это относительно современная концепция.
Майкл Стум
-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переменной увеличивается на единицу.

Надеюсь, теперь это понятно.

Krie999
источник
Но это не решает актуальный вопрос: почему разработчики C спрашивают об этом больше, чем другие. ОП понимает операторов.
Мартейн Питерс
Также этот ответ фактически неверен. ++iне быстрее, и i++не создает копию. Кроме того, ++iведет себя немного по-другому в C, чем в C ++, не говоря уже о других языках.
ММ