C / C ++: GOTO быстрее, чем WHILE и FOR? - PullRequest
8 голосов
/ 20 марта 2011

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

  1. goto петля

    int i=3;
    loop:
    printf("something");
    if(--i) goto loop;
    
  2. while петля

    int i=3;
    while(i--) {
        printf("something");
    }
    
  3. for петля

    for(int i=3; i; i--) {
        printf("something");
    }
    

Ответы [ 8 ]

16 голосов
/ 20 марта 2011

Вообще говоря, циклы for и while компилируются так же, как goto, поэтому обычно это не имеет значения.Если у вас есть сомнения, вы можете попробовать все три и посмотреть, что займет больше времени.Скорее всего, вы не сможете измерить разницу, даже если вы зациклились миллиард раз.

Если вы посмотрите на этот ответ , вы увидите, что компилятор может сгенерировать точноодин и тот же код для for, while и goto (только в этом случае не было условий).

6 голосов
/ 20 марта 2011

Напишите короткие программы, затем сделайте следующее:

gcc -S -O2 p1.c 
gcc -S -O2 p2.c 
gcc -S -O2 p3.c 

Анализируйте вывод и посмотрите, есть ли какая-либо разница.Обязательно добавьте некоторый уровень непредсказуемости, чтобы компилятор не оптимизировал программу до нуля.

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

Скорость и эффективность - это отличная вещь для беспокойства, но в 99% случаев это связано справильные структуры данных и алгоритмы ... не беспокоясь о том, быстрее ли for, чем while или goto и т. д.

4 голосов
/ 20 марта 2011

Единственный раз, когда я видел аргумент в пользу goto, был в одной из статей или книг У. Ричарда Стивенса. Его точка зрения заключалась в том, что в очень критической по времени секции кода (я полагаю, что его примером был сетевой стек), вложив блоки if / else со связанным кодом обработки ошибок, можно было бы переделать, используя goto таким образом, это имело важное значение.

Лично я не достаточно хороший программист, чтобы спорить с работой Стивенса, поэтому я не буду пытаться. goto может быть полезным для проблем, связанных с производительностью, но ограничения при достаточно строги.

3 голосов
/ 20 марта 2011

Вероятно, это зависит и от компилятора, от оптимизатора и от архитектуры.

Например, код if(--i) goto loop; - это условный тест , за которым следует безусловная ветвь .Компилятор может просто сгенерировать соответствующий код или он может быть достаточно умным (хотя компилятор, у которого не было хотя бы такого большого количества умов, может не стоить много), чтобы сгенерировать одну инструкцию условного перехода .while(i--), с другой стороны, уже является условной ветвью на уровне источника, поэтому преобразование в условную ветвь на уровне машины может быть более простым, независимо от сложности реализации компилятора или оптимизатора.

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

В ваших примерах printf () в цикле будет доминировать над любым временем в любом случае;что-то более простое в цикле облегчит наблюдение за различиями.Я хотел бы предложить пустой цикл, а затем объявить i volatile, чтобы предотвратить оптимизацию цикла до нуля.

2 голосов
/ 20 марта 2011

Не должно быть существенной разницы между всеми циклами и goto. За исключением идеи, что компилятор, скорее всего, вообще не будет пытаться оптимизировать GOTO-вещи.

И нет большого смысла пытаться оптимизировать сгенерированные компилятором вещи в циклах. Более разумно оптимизировать код внутри цикла или сократить количество итераций и т. Д.

2 голосов
/ 20 марта 2011

Пока вы генерируете тот же поток управления, что и в обычном цикле, почти любой приличный компилятор может и будет генерировать один и тот же код, независимо от того, используете ли вы для него for, while и т. Д.

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

1 голос
/ 21 марта 2011

Я думаю, что будет какой-то код после компилятора в нормальном состоянии.

На самом деле я думаю, что goto иногда очень удобно, хотя его трудно читать.

0 голосов
/ 21 марта 2011

Есть несколько нишевых вертикалей, в которых goto все еще широко используется в качестве стандартной практики некоторыми очень умными людьми, и в этих настройках нет предвзятого отношения к goto. Раньше я работал в компании, специализирующейся на симуляции, где весь локальный код на Fortran содержал тонны gotos, команда была очень умной, а программное обеспечение работало почти безупречно.

Итак, мы можем оставить в стороне достоинство goto, и если вопрос заключается просто в сравнении циклов, то мы делаем это путем профилирования и / или сравнения кода сборки. Тем не менее, вопрос включает в себя такие утверждения, как printf и т. Д. Вы не можете обсуждать оптимизацию логики управления циклами при этом. Также, как отмечали другие, все эти циклы будут генерировать ОЧЕНЬ похожие машинные коды.

Все условные ветви считаются «принятыми» (истинными) в конвейерных архитектурах процессоров в любом случае до фазы декодирования, в дополнение к небольшим циклам, которые обычно расширяются до состояния без цикла. Таким образом, в соответствии с пунктом Харпера выше, для goto нереально иметь какое-либо преимущество в простом управлении циклами (точно так же, как и в то время, когда они не имеют преимущества друг над другом). GOTO имеет смысл, как правило, в нескольких вложенных циклах или нескольких вложенных if, при добавлении дополнительного условия, проверенного goto, в КАЖДЫЙ из вложенных циклов или вложенных ifs неоптимально.

При оптимизации операции поиска в простом цикле использование часового иногда более эффективно, чем что-либо еще. По сути, добавляя фиктивное значение в конец массива, вы можете избежать проверки того, что два условия (конец массива и найденное значение) являются только одним условием (найденное значение), и это экономит на операциях cmp внутри. Я не знаю, автоматически ли это делают компиляторы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...