Является ли "for(;;)" быстрее, чем "while (TRUE)"? Если нет, то почему люди используют это?

for (;;) {
    //Something to be done repeatedly
}

Я видел, что такого рода вещи часто используются, но я думаю, что это довольно странно... Разве не было бы намного яснее сказать, while(true), Или что-то вдоль этих линий?

Я предполагаю, что (как причина, по которой многие программисты прибегают к загадочному коду), это крошечный запас быстрее?

Почему и стоит ли оно того? Если так, то почему бы просто не определить это так:

#define while(true) for(;;)

Смотрите также: Что быстрее: while(1) или while(2)?

21 ответ

Решение
  1. Это не быстрее.
  2. Если вам действительно важно, скомпилируйте с ассемблером выходные данные для вашей платформы и посмотрите.
  3. Это не важно Это никогда не имеет значения. Напишите свои бесконечные циклы, как вам нравится.

Я предпочитаю for(;;) по двум причинам.

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

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

Тогда как с while(true)Ну, что тут общего с чем-то? Я не заинтересован в цикле, пока истина не станет ложной, что буквально говорит эта форма (цикл, пока истина - истина). Я просто хочу зациклить.

И нет, нет абсолютно никакой разницы в производительности.

Лично я пользуюсь for (;;) потому что там нет никаких цифр, это просто ключевое слово. Я предпочитаю это while (true), while (1), while (42), while (!0) и т. д.

Из-за Денниса Ричи

  • Я начал использовать for (;;) потому что именно так Деннис Ричи делает это в K&R, и при изучении нового языка я всегда стараюсь подражать умным парням.

  • Это идиоматический C/C++. Вероятно, в конечном итоге лучше привыкнуть к этому, если вы планируете многое делать в пространстве C/C++.

  • Ваш #define не будет работать, так как вещь #define'd должна выглядеть как идентификатор C.

  • Все современные компиляторы генерируют одинаковый код для двух конструкций.

Я предпочитаю for (;;) потому что это наиболее последовательно в разных C-подобных языках.

В C++ while (true) хорошо, но в C вы зависите от заголовка, чтобы определить true, еще TRUE это также часто используемый макрос. Если вы используете while (1) это правильно в C и C++ и JavaScript, но не в Java или C#, которые требуют, чтобы условие цикла было логическим, например while (true) или же while (1 == 1), В PHP ключевые слова нечувствительны к регистру, но язык предпочитает использование заглавных букв TRUE,

Тем не мение, for (;;) всегда полностью правильно во всех этих языках.

Это конечно не быстрее в любом здравомыслящем компиляторе. Они оба будут скомпилированы в безусловные переходы. Версия for легче набрать (как сказал Нейл) и будет понятна, если вы понимаете синтаксис цикла.

Если вам интересно, вот что дает мне gcc 4.4.1 для x86. Оба используют инструкцию JMP x86.

void while_infinite()
{
    while(1)
    {
    puts("while");
    }
}

void for_infinite()
{
    for(;;)
    {
    puts("for");
    }
}

компилируется в (частично):

.LC0:
.string "while"
.text
.globl while_infinite
    .type   while_infinite, @function
while_infinite:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $24, %esp
.L2:
    movl    $.LC0, (%esp)
    call    puts
    jmp .L2
    .size   while_infinite, .-while_infinite
    .section    .rodata
.LC1:
    .string "for"
    .text
.globl for_infinite
    .type   for_infinite, @function
for_infinite:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $24, %esp
.L5:
    movl    $.LC1, (%esp)
    call    puts
    jmp .L5
    .size   for_infinite, .-for_infinite

Я лично предпочитаю for (;;) идиома (которая будет компилироваться в тот же код, что и while (TRUE),

С помощью while (TRUE) может быть более читабельным в некотором смысле, я решил использовать for (;;) идиома, потому что это выделяется.

Конструкция бесконечного цикла должна быть легко замечена или вызвана в коде, и я лично думаю, что for (;;) стиль делает это немного лучше, чем while (TRUE) или же while (1),

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

Я видел, что некоторые люди предпочитают это, потому что у них есть #define где-то вроде этого:

#define EVER ;;

Что позволяет им написать это:

for (EVER)
{
    /* blah */
}

Как насчет (если ваш язык поддерживает это):

start:
/* BLAH */
goto start;

Там нет никакой разницы с точки зрения машинного кода, который генерируется.

Тем не менее, просто чтобы уловить тенденцию, я бы сказал, что форма while(TRUE) гораздо более читабельна и интуитивно понятна, чем для (;;), и что читаемость и ясность являются гораздо более важными причинами для руководящих принципов кодирования, чем любые причины, которые я ' я слышал о подходе for(;;) (я предпочитаю основывать свои руководящие принципы кодирования на здравом рассуждении и / или доказательстве эффективности самостоятельно).

while(true)

генерирует предупреждение с Visual Studio (условие является постоянным). В большинстве мест, где я работал, компилируются производственные сборки с предупреждениями об ошибках. Так

for(;;)

является предпочтительным.

Оба должны быть одинаковыми, если ваш код оптимизирован компилятором. Чтобы объяснить, что я имею в виду под оптимизацией, вот пример кода, написанного в MSVC 10:

int x = 0;

while(true) // for(;;)
{
    x +=1;

    printf("%d", x);
}

Если вы строите его в режиме отладки (без какой-либо оптимизации (/ Od)), разборка показывает явную разницу. Есть дополнительные инструкции для true состояние внутри while,

while(true)
00D313A5  mov         eax,1                //extra 
00D313AA  test        eax,eax              //extra
00D313AC  je          main+39h (0D313B9h)  //extra
    {
        x +=1;
00D313AE  mov         eax,dword ptr [x]  
00D313B1  add         eax,1  
00D313B4  mov         dword ptr [x],eax  
    printf("%d", x);
    ...
    }
00D313B7  jmp         main+25h (0D313A5h)  


for(;;)
    {
        x +=1;
00D213A5  mov         eax,dword ptr [x]  
00D213A8  add         eax,1  
00D213AB  mov         dword ptr [x],eax  
    printf("%d", x);
    ...
    }
00D213AE  jmp         main+25h (0D213A5h)  

Однако, если вы строите свой код в режиме Release (с максимальной скоростью по умолчанию (/ O2)), вы получите одинаковый вывод для обоих. Оба цикла сводятся к одной инструкции перехода.

for(;;)
    {
        x +=1;
01291010  inc         esi  

        printf("%d", x);
    ...
    }
0129101C  jmp         main+10h (1291010h)  

    while(true)
    {
        x +=1;
00311010  inc         esi  

        printf("%d", x);
    ...
    }
0031101C  jmp         main+10h (311010h)  

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

Не просто известный шаблон, но стандартная идиома в C (и C++)

Это вопрос личных предпочтений, какой путь быстрее. Лично я сенсорный человек и никогда не смотрю на свою клавиатуру во время программирования - я могу коснуться всех 104 клавиш на моей клавиатуре.

Я нахожу, если быстрее набрать "while (TRUE)".

Я мысленно добавил некоторые измерения движения пальцев и суммировал их. "for(;;)" имеет около 12 значений ширины клавиш назад и четвертого (между клавишами "home" и клавишами, а также между клавишами "home" и клавишей SHIFT) "while (TRUE)" имеет около 14 значений ширины клавиш назад и четвёртый.

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

(Мой тест TypingTest.com = 136 WPM)

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

Однако я предлагаю вам предпочесть for(;;) по следующим причинам:

  • несколько компиляторов, которые я использовал, будут генерировать предупреждение о постоянном выражении для while (true) с соответствующими настройками уровня предупреждения.

  • в вашем примере макрос TRUE может быть определен не так, как вы ожидаете

  • Есть много возможных вариантов бесконечного цикла while, таких как while(1), while(true), while(1==1) так далее.; так for(;;) может привести к большей согласованности.

Все хорошие ответы - поведение должно быть точно таким же.

ОДНАКО - Просто предположим, что это имело значение. Предположим, что одна из них взяла еще 3 инструкции за итерацию.

Должны ли вы заботиться?

ТОЛЬКО если то, что вы делаете внутри цикла, почти ничего, что почти никогда не происходит.

Я хочу сказать, что есть микрооптимизация и макрооптимизация. Микрооптимизация похожа на "стрижку, чтобы похудеть".

for(;;Sleep(50))
{
    // Lots of code
}

Это яснее, чем:

while(true)
{
    // Lots of code
    Sleep(50);
}

Не то чтобы это применимо, если вы не используете Sleep(),

Наиболее важной причиной использования "for(;;)" является боязнь использовать "while(TRUE)" при выполнении исследовательского программирования. Проще контролировать количество повторений с помощью "for", а также легче преобразовать цикл "for" в бесконечный.

Например, если вы создаете рекурсивную функцию, вы можете ограничить количество вызовов этой функции перед преобразованием в бесконечный цикл.

    for(int i=0;i<1000;i++) recursiveFunction(oneParam);

Когда я уверен в своей функции, тогда я преобразую ее в бесконечный цикл:

    for(;;) recursiveFunction(oneParam);

Цикл "навсегда" популярен во встроенных системах как фоновый цикл. Некоторые люди реализуют это как:

for (; ;)
{
 // Stuff done in background loop
}

И иногда это реализуется как:

while (TRUE /* or use 1 */)
{
 // Stuff done in background loop
}

И еще одна реализация:

do
{
 // Stuff done in background loop
} while (1 /* or TRUE */);

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

Я предполагаю, что while(true) более читабельно, чем for(;;) - похоже, программист пропускает что-то в цикле:)

и кто заботится, какой из них быстрее, если таковые имеются

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

Для меня это просто придирки, потому что любой программист на C должен уметь мгновенно распознавать и то, и другое. while(1) а также for(;;) как бесконечные петли.

Ваше определение не сработает. Однако вы МОЖЕТЕ (но не должны) это делать:

      #define repeat for(;;)

int main(void)
{
    repeat {
        puts("Hello, World");
    }
}

Но на самом деле, НЕ делайте этого ...

Другие вопросы по тегам