То, что сказал ваш учитель, было некоторым косвенным утверждением без особых разъяснений.
Это НЕ то, что декремент быстрее, чем инкремент, но вы можете создать гораздо более быстрый цикл с декрементом, чем с инкрементом.
Не вдаваясь в подробности, без использования счетчика циклов и т. Д. Ниже важны только скорость и счетчик циклов (не ноль).
Вот как большинство людей реализуют цикл с 10 итерациями:
int i;
for (i = 0; i < 10; i++)
{
//something here
}
В 99% случаев это все, что может понадобиться, но наряду с PHP, PYTHON, JavaScript существует целый мир критически важного по времени программного обеспечения (обычно встроенного, ОС, игр и т. Д.), Где такты процессора действительно важны, поэтому кратко посмотрите на сборку код:
int i;
for (i = 0; i < 10; i++)
{
//something here
}
после компиляции (без оптимизации) скомпилированная версия может выглядеть так (VS2015):
-------- C7 45 B0 00 00 00 00 mov dword ptr [i],0
-------- EB 09 jmp labelB
labelA 8B 45 B0 mov eax,dword ptr [i]
-------- 83 C0 01 add eax,1
-------- 89 45 B0 mov dword ptr [i],eax
labelB 83 7D B0 0A cmp dword ptr [i],0Ah
-------- 7D 02 jge out1
-------- EB EF jmp labelA
out1:
Весь цикл состоит из 8 инструкций (26 байт). В нем - фактически 6 инструкций (17 байт) с 2 ветками. Да, да, я знаю, что это можно сделать лучше (это всего лишь пример).
Теперь рассмотрим эту частую конструкцию, которую вы часто найдете в написании встроенного разработчика:
i = 10;
do
{
//something here
} while (--i);
Он также повторяется 10 раз (да, я знаю, что значение отличается по сравнению с показанным для цикла, но здесь нас интересует количество итераций).
Это может быть скомпилировано в это:
00074EBC C7 45 B0 01 00 00 00 mov dword ptr [i],1
00074EC3 8B 45 B0 mov eax,dword ptr [i]
00074EC6 83 E8 01 sub eax,1
00074EC9 89 45 B0 mov dword ptr [i],eax
00074ECC 75 F5 jne main+0C3h (074EC3h)
5 инструкций (18 байт) и всего одна ветка. На самом деле в цикле 4 инструкции (11 байт).
Лучше всего то, что некоторые процессоры (включая x86 / x64-совместимые) имеют инструкцию, которая может уменьшить регистр, затем сравнить результат с нулем и выполнить ветвление, если результат отличается от нуля. Практически ВСЕ процессоры ПК реализуют эту инструкцию. Используя его, цикл фактически представляет собой одну (да, одну) 2-байтовую инструкцию:
00144ECE B9 0A 00 00 00 mov ecx,0Ah
label:
// something here
00144ED3 E2 FE loop label (0144ED3h) // decrement ecx and jump to label if not zero
Должен ли я объяснить, что быстрее?
Теперь, даже если конкретный ЦП не реализует вышеприведенную инструкцию, все, что требуется для эмуляции, - это декремент, за которым следует условный переход, если результат предыдущей инструкции окажется равным нулю.
Поэтому, независимо от некоторых случаев, вы можете указать в качестве комментария, почему я не прав и т. Д., И т. Д. Я ПОДЧЕРКИВАЮ - ДА, НУЖНО БЫТЬ ЗАКРЫТО, если вы знаете, как, почему и когда.
PS. Да, я знаю, что мудрый компилятор (с соответствующим уровнем оптимизации) переписывает цикл (с восходящим счетчиком цикла) в do..в то же время эквивалентно для итераций постоянного цикла ... (или развернуть его) ...