C / C++: GOTO быстрее, чем WHILE и FOR?
Я знаю, что все ненавидят Гото и никто этого не рекомендует. Но дело не в этом. Я просто хочу знать, какой код самый быстрый:
-
на
goto
циклint i=3; loop: printf("something"); if(--i) goto loop;
-
на
while
циклint i=3; while(i--) { printf("something"); }
-
на
for
циклfor(int i=3; i; i--) { printf("something"); }
8 ответов
вообще говоря, for
и while
циклы компилируются так же, как goto
, поэтому обычно это не имеет значения. Если у вас есть сомнения, вы можете попробовать все три и посмотреть, что займет больше времени. Скорее всего, вы не сможете измерить разницу, даже если вы сделаете цикл миллиард раз.
если вы посмотрите на ответ, вы увидите, что компилятор может генерировать точно такой же код for
, while
и goto
(только в этом случае нет состояние).
напишите короткие программы, затем сделайте следующее:
gcc -S -O2 p1.c
gcc -S -O2 p2.c
gcc -S -O2 p3.c
проанализируйте вывод и посмотрите, есть ли какая-либо разница. Не забудьте ввести некоторый уровень непредсказуемости, чтобы компилятор не оптимизировал программу до нуля.
компиляторы делают большую работу по оптимизации этих тривиальных проблем. Я бы предложил не беспокоиться об этом, а вместо этого сосредоточиться на том, что делает вас более продуктивным программистом.
скорость и эффективность большая вещь, котор нужно потревожиться об этом, но 99% времени, которое включает в себя использование надлежащих структур данных и алгоритмов... не беспокоясь о том,for
быстрее while
или goto
, etc.
единственный раз, когда я видел аргумент, сделанный для Гото, был в одной из статей или книг У. Ричарда Стивенса. Он подчеркивал, что в очень критический по времени раздел кода (я считаю, что его примером был сетевой стек), вложив блоки if/else с соответствующим кодом обработки ошибок, можно было бы переделать с помощью goto таким образом, чтобы сделать ценную разницу.
лично я не настолько хороший программист, чтобы спорить с работой Стивенса, поэтому я не буду пытаться. идти к can полезно для вопросов, связанных с производительностью, но пределы , когда то есть так довольно строги.
это, вероятно, как компилятор, оптимизатор и специфичная архитектура.
например код if(--i) goto loop;
Это условный тест затем безусловная филиала. Компилятор может просто генерировать соответствующий код или быть достаточно умным (хотя компилятор, у которого не было по крайней мере столько умов, может не стоить многого), чтобы создать один условное ветвление инструкция. while(i--)
С другой стороны уже условная ветвь на исходном уровне, поэтому перевод в условную ветвь на машинном уровне может быть более похожим, независимо от сложности реализации компилятора или оптимизатора.
В конце концов, разница likley для того чтобы быть минутой и только если есть очень много итераций необходимо, и как вы должны ответить на этот вопрос заключается в создании кода для конкретной задачи и компилятор (и параметры компилятора) интересов, а также проверить полученные код машинного уровня или непосредственно измеряет время выполнения.
в ваших примерах printf () в цикле будет доминировать в любом случае; что-то более простое в цикле облегчит наблюдение различий. Я бы предложил пустой цикл, а затем объявление i
volatile
чтобы предотвратить оптимизацию цикла до нуля.
пока вы генерируете тот же поток управления, что и обычный цикл, почти любой приличный компилятор может и будет производить тот же код, используете ли вы for
, while
, etc. для него.
вы можете получить что-то от использования goto
, но обычно только если вы генерируете поток управления, который обычный цикл просто не может (по крайней мере, чисто). Типичным примером является переход в середину цикла, чтобы получить полтора цикла, который является нормальным циклом большинства языков утверждения (включая C) не обеспечивают чисто.
не должно быть никакой существенной разницы между всеми петлями и goto. Кроме идеи, что компилятор скорее всего вообще не будет пытаться оптимизировать Гото-вещи.
и нет большого смысла пытаться оптимизировать генерируемые компилятором вещи в циклах. Больше смысла оптимизировать код внутри цикла или уменьшить количество итераций или так далее.
Я думаю, что будет какой-то код после компилятора при условии nornal.
на самом деле я думаю, что Гото очень удобно иногда, хотя это трудно читать.
есть несколько нишевых вертикалей, где goto по-прежнему широко используется в качестве стандартной практики, некоторыми очень умными людьми, и в этих настройках нет предвзятости против goto. Раньше я работал в компании, специализирующейся на моделировании, где весь местный код fortran имел тонны goto, команда была супер умной, и программное обеспечение работало почти безупречно.
таким образом, мы можем оставить заслугу Гото в стороне, и если вопрос только в том, чтобы сравнить петли, то мы делаем это путем профилирования и / или сравнение кода сборки. Тем не менее, вопрос включает в себя такие утверждения, как printf и т. д. При этом вы не можете обсуждать оптимизацию логики управления циклом. Кроме того, как указывали другие, данные циклы будут генерировать очень похожие машинные коды.
все условные ветви считаются "принятыми" (true) в конвейерных архитектурах процессоров в любом случае до фазы декодирования, в дополнение к небольшим петлям, которые обычно расширяются, чтобы быть бесповоротными. Итак, в в соответствии с точкой Харпера выше, нереально, чтобы Гото имел какое-либо преимущество в простом управлении циклом (так же, как для или в то время не имеют преимущества друг над другом). GOTO имеет смысл обычно в нескольких вложенных циклах или нескольких вложенных ifs, при добавлении дополнительного условия, проверенного goto в каждый из вложенных циклов или вложенных ifs, является неоптимальным.
при оптимизации операции поиска в простом цикле использование sentinal иногда более эффективно, чем что-нибудь еще. По сути, добавив фиктивное значение в конце массива, вы можете избежать проверки того, что два условия (конец массива и найденное значение) являются только одним условием (найденное значение), и это экономит операции cmp внутри. Я не знаю, делают ли компиляторы это автоматически или нет.