Возможно, это не имеет значения для компилятора после его оптимизации, но в C / C ++ я вижу, что большинство людей создают цикл for в виде:
for (i = 0; i < arr.length; i++)
где приращение выполняется с помощью post fix ++. Я получаю разницу между двумя формами. i ++ возвращает текущее значение i, но затем добавляет 1 к i в тишине. ++ i сначала добавляет 1 к i и возвращает новое значение (будучи еще 1 больше, чем я).
Я бы подумал, что i ++ требует немного больше работы, поскольку предыдущее значение нужно сохранить в дополнение к следующему значению: Push * (& i) для стека (или загрузка для регистрации); приращение * (& i). Versus ++ i: Increment * (& i); затем используйте * (& i) по мере необходимости.
(Я понимаю, что операция «Increment * (& i)» может включать в себя нагрузку на регистр, в зависимости от дизайна ЦП. В этом случае i ++ потребуется либо другой регистр, либо push-файл).
Во всяком случае, в какой момент и почему, i ++ стал более модным?
Я склонен верить ажеглову: это педагогическая вещь, и поскольку большинство из нас делает C / C ++ в системе Window или * nix, где компиляторы имеют высокое качество, никто не пострадал.
Если вы используете компилятор низкого качества или интерпретируемую среду, вам может потребоваться быть чувствительным к этому. Конечно, если вы делаете продвинутый C ++ или драйвер устройства или встроенную работу, мы надеемся, что вы достаточно опытные, чтобы это было неважно. (У собак есть природа Будды? Кто действительно должен знать?)
Моя теория (почему я ++ более моден) заключается в том, что, когда люди учатся C (или C ++), они в конечном итоге учатся кодировать итерации следующим образом:
while( *p++ ) { ... }
Обратите внимание, что здесь важна форма постфиксирования (с использованием формы инфикса создается одноразовая ошибка).
Когда придет время написать цикл for
где ++i
или i++
действительно не имеет значения, может быть более естественным использовать постфиксную форму.
ADDED: То, что я написал выше, действительно относится к примитивным типам. Когда вы кодируете что-то с примитивными типами, вы, как правило, делаете что-то быстро и делаете то, что приходит естественно. Это важное предостережение, которое мне нужно приложить к моей теории.
Если ++
является перегруженным оператором на классе C ++ (возможность, предложенная Rich K. в комментариях), то, конечно, вам нужно с особой тщательностью кодировать циклы с участием таких классов, а не делать простые вещи, которые приходят естественным образом.
Неважно, что вы используете. На некоторых крайне устаревших машинах и в некоторых случаях с C ++ ++i
более эффективен, но современные компиляторы не сохраняют результат, если он не сохраняется. Что касается того, когда стало популярным postincriment in for
loops, моя копия второго выпуска K & R использует i++
на стр. 65 (первый цикл, который я нашел, когда просматривал.)
По какой-то причине i++
стал более идиоматичным в C, хотя он создает ненужную копию . (Я думал, что это было через K & R, но я вижу, что это обсуждается в других ответах.) Но я не думаю, что есть разница в производительности на C, где он используется только на встроенных модулях, для которых компилятор может оптимизировать работу копирования ,
Однако это имеет значение в C ++, где i
могу быть определяемым пользователем типом, для которого operator++()
перегружен. Компилятор, возможно, не сможет утверждать, что операция копирования не имеет видимых побочных эффектов и, следовательно, не сможет ее устранить.
Для целых типов две формы должны быть эквивалентными, если вы не используете значение выражения. Это больше не верно в мире C ++ с более сложными типами, но сохраняется в имени языка.
Я подозреваю, что «i ++» стал более популярным в первые дни, потому что это стиль, используемый в оригинальной книге K & R «The C Programming Language». Вы должны спросить их, почему они выбрали этот вариант.
Что касается причины, вот что говорит K & R по этому вопросу:
вам придется попросить Дениса (и это может быть в бумаге HOPL). У меня тусклая память, что она была связана с операцией post-increment в pdp-11, хотя помимо этого я не знаю, поэтому не цитируйте меня.
в c ++ предпочтительный стиль для итераторов на самом деле ++ i для некоторой тонкой причины реализации.
Нет особой причины, она просто стала модной. Полученный код идентичен на PDP-11, просто инструкция inc, без автоинкремента.
Возвращаясь немного дальше, чем K & R, я посмотрел на своего предшественника: учебник Кернигана C (~ 1975). Здесь первые несколько примеров используют ++n
. Но каждый цикл for
использует i++
. Поэтому, чтобы ответить на ваш вопрос: почти с самого начала i++
стал более модным.
Потому что, как только вы начнете использовать «++ i», люди будут смущены и любопытны. Они будут останавливать там повседневную работу и начинать поиски для объяснений. Через 12 минут они перейдут в переполнение стека и зададут такой вопрос. И вуаля, ваш работодатель просто потратил еще 10 долларов
На некотором уровне это идиоматический код C. Это как раз то, как обычно делаются. Если это ваше узкое место в производительности, вы, вероятно, работаете над уникальной проблемой.
Однако, глядя на мой K & R Язык программирования C , 1-е издание, первый экземпляр, который я нахожу для i в цикле (стр. 38), действительно использует ++ i, а не i ++.
По-моему, это стало более модным с созданием C ++, поскольку C ++ позволяет вам вызывать ++ на нетривиальных объектах.
Хорошо, я уточняю: если вы вызываете i++
а i
– нетривиальный объект, то сохранение копии, содержащей значение i до инкремента, будет дороже, чем, например, указатель или целое число.
Я думаю, что мои предшественники правы в отношении побочных эффектов выбора постинкремента по сравнению с преинкрементальным.
Для его fashonability, это может быть так же просто, как вы начинаете все три выражения внутри оператора for одним и тем же повторяющимся способом, к чему, по-видимому, стремится человеческий мозг.
Я бы добавил, что другие люди сказали вам, что главное правило: быть последовательным. Выберите один и не используйте другой, если это не конкретный случай.
Если цикл слишком длинный, вам необходимо перезагрузить значение в кеше, чтобы увеличить его до перехода к началу. Что вам не нужно с ++ i, без кэша.
В C все операторы, которые приводят к переменной, имеющей новое значение, кроме префикса inc / dec, изменяют левую переменную (i = 2, i + = 5 и т. Д.). Поэтому в ситуациях, когда ++ i и i ++ могут быть взаимозаменяемы, многие люди более удобны с i ++, потому что оператор находится справа, изменяя левую переменную
Скажите, пожалуйста, если это первое предложение неверно, я не эксперт C.