Ответ 1
- Это не быстрее.
- Если вам действительно интересно, скомпилируйте с выходом ассемблера для своей платформы и посмотрите, чтобы увидеть.
- Это не имеет значения. Это никогда не имеет значения. Напишите свои бесконечные петли, как вам нравится.
for (;;) {
//Something to be done repeatedly
}
Я видел такие вещи, которые много использовали, но я думаю, что это довольно странно...
Не было бы гораздо яснее сказать while(true)
или что-то в этом роде?
Я предполагаю, что (как и причина, по которой многие-программисты прибегают к загадочному коду), это крошечный запас быстрее?
Почему, и это действительно стоит? Если да, почему бы просто не определить его так:
#define while(true) for(;;)
Я предпочитаю for(;;)
по двум причинам.
Во-первых, некоторые компиляторы производят предупреждения на while(true)
(что-то вроде "условие цикла постоянное" ). Предотвращение предупреждений - это всегда хорошо.
Другим является то, что я думаю, что for(;;)
более ясный и более разговорный.
Я хочу бесконечный цикл. Он буквально не имеет состояния, это ни на что не зависит. Я просто хочу, чтобы он продолжался вечно, пока я не сделаю что-то, чтобы вырваться из него.
В то время как с while(true)
, ну, что истинно, что-то нужно делать? Меня не интересует цикл, пока true не станет ложным, и это то, что эта форма буквально говорит (цикл while true). Я просто хочу зациклиться.
И нет, нет никакой разницы в производительности.
Лично я использую for (;;)
, потому что в нем нет никаких чисел, это просто ключевое слово. Я предпочитаю его while (true)
, while (1)
, while (42)
, while (!0)
и т.д. И т.д.
Это, конечно, не быстрее в любом разумном компиляторе. Оба они будут скомпилированы в безусловные прыжки. Для версии проще набирать (как сказал Нил), и будет ясно, если вы поймете для синтаксиса цикла.
Если вам интересно, вот что gcc 4.4.1 дает мне для x86. Оба используют команду x86 JMP.
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 (;;)
, потому что это способ, которым Деннис Ричи делает это в K & R, и когда я изучаю новый язык, я всегда стараюсь подражать умным парням.
Это идиоматический C/С++. Вероятно, лучше в конечном итоге привыкнуть к нему, если вы планируете многое сделать на пространстве C/С++.
Ваш #define
не будет работать, поскольку предмет # define'd должен выглядеть как идентификатор C.
Все современные компиляторы будут генерировать один и тот же код для двух конструкций.
Я предпочитаю for (;;)
, потому что он наиболее согласован в разных языках C.
В С++ while (true)
отлично, но в C вы зависите от заголовка для определения true
, но true
также является широко используемым макросом. Если вы используете while (1)
, это правильно в C и С++ и JavaScript, но не Java или С#, для чего условие цикла должно быть логическим, например while (true)
или while (1 == 1)
. В PHP ключевые слова не чувствительны к регистру, но язык предпочитает капитализацию true
.
Однако for (;;)
всегда полностью корректен на всех этих языках.
Я лично предпочитаю идиому for (;;)
(которая будет компилироваться с тем же кодом, что и while (TRUE)
.
Использование while (TRUE)
может быть более читаемым в некотором смысле, я решил использовать идиому for (;;)
, потому что она выделяется.
Конструкцию бесконечного цикла следует легко заметить или вызвать в коде, и я лично считаю, что стиль for (;;)
делает это немного лучше, чем while (TRUE)
или while (1)
.
Кроме того, я помню, что некоторые компиляторы выдают предупреждения, когда управляющее выражение цикла while является константой. Я не думаю, что это случается слишком много, но достаточно возможностей для ложных предупреждений достаточно, чтобы я хотел этого избежать.
Я видел, как некоторые люди предпочитают это, потому что у них есть #define где-то вроде этого:
#define EVER ;;
Это позволяет им написать это:
for (EVER)
{
/* blah */
}
Как насчет (если ваш язык поддерживает его):
start:
/* BLAH */
goto start;
while(true)
генерирует предупреждение в Visual Studio (условие является постоянным). Большинство мест, в которых я работал, компилируют сборки сборки с предупреждениями как ошибки. Так
for(;;)
является предпочтительным.
Не только хорошо известный шаблон, но и стандартная идиома в C (и С++)
Нет никакой разницы в терминах генерируемого машинного кода.
Однако, чтобы оценить тренд, я бы сказал, что форма while (TRUE) более читаема и интуитивно понятна, чем для (;;), и что читаемость и ясность являются гораздо более важными причинами для правил кодирования, чем любые причины, которые я слышал для подхода for (;;) (я предпочитаю основывать свои правила кодирования на твердых рассуждениях и/или доказательстве эффективности сам).
Оба должны быть одинаковыми, если ваш код оптимизирован компилятором. Чтобы объяснить, что я подразумеваю под оптимизацией, вот пример кода, написанного в MSVC 10:
int x = 0;
while(true) // for(;;)
{
x +=1;
printf("%d", x);
}
Если вы построите его в режиме отладки (без какой-либо оптимизации (/Od)), демонстрация показывает явное различие. В true
есть дополнительные инструкции для true
.
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)
Однако, если вы создадите свой код в режиме деблокирования (по умолчанию Максимизировать скорость (/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)
В зависимости от того, что вы будете использовать, не имеет значения для достойного компилятора с оптимизацией скорости.
Это вопрос личных предпочтений, какой путь быстрее. Лично я являюсь touchtypist и никогда не смотрю на свою клавиатуру, во время программирования - я могу коснуться всех 104 клавиш на моей клавиатуре.
Я нахожу, если быстрее набрать "while (TRUE)".
Я мысленно добавил некоторые измерения движения пальца и суммировал их. "for (;;)" имеет около 12 ключевых ширины движений назад и четвертое (между домашними клавишами и клавишами, между домашними клавишами и клавишей SHIFT) "while (TRUE)" имеет около 14 ключевых ширины движений назад и четвертый.
Тем не менее, я намного менее подвержен ошибкам при вводе последнего. Я мысленно думаю в словах за раз, поэтому я нахожу, что быстрее набирать такие вещи, как "nIndex", чем аббревиатуры типа "nIdx", потому что я должен на самом деле мысленно описать надпись, а не говорить об этом в моем сознании и позволить моим пальцам автоматически (например, кататься на велосипеде)
(Мой тест TypingTest.com = 136 WPM)
Все хорошие ответы - поведение должно быть точно таким же.
ОДНАКО - Просто предположим, что это имеет значение. Предположим, что один из них потребовал еще 3 инструкции на итерацию.
Вам все равно?
ТОЛЬКО, если то, что вы делаете внутри цикла, почти ничего, что почти никогда не бывает.
Я хочу сказать, что есть микро-оптимизация и макро-оптимизация. Микро-оптимизация похожа на "получение стрижки, чтобы похудеть".
for(;;Sleep(50))
{
// Lots of code
}
Яснее, чем:
while(true)
{
// Lots of code
Sleep(50);
}
Не то, чтобы это применимо, если вы не используете Sleep()
.
Я не могу себе представить, что достойный компилятор будет генерировать любой другой код. Даже если бы это было так, не было бы никакого способа определить без тестирования конкретного компилятора, который был бы более эффективным.
Однако я предлагаю вам выбрать for(;;)
по следующим причинам:
ряд компиляторов, которые я использовал, будет генерировать предупреждение о постоянном выражении для while (true) с соответствующими настройками уровня предупреждений.
в вашем примере макрос TRUE не может быть определен так, как вы ожидаете
существует множество возможных вариантов бесконечного цикла while, например while(1)
, while(true)
, while(1==1)
и т.д.; поэтому for(;;)
может привести к большей согласованности.
Цикл "forever" популярен во встроенных системах в качестве фонового цикла. Некоторые люди реализуют его как:
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 (;;)" - это страх использования "while (TRUE)", когда вы выполняете поисковое программирование. Легче контролировать количество повторений с помощью "for", а также проще преобразовать цикл "for" в бесконечный.
Например, если вы создаете рекурсивную функцию, вы можете ограничить количество вызовов функции перед преобразованием в бесконечный цикл.
for(int i=0;i<1000;i++) recursiveFunction(oneParam);
Когда я уверен в своей функции, я конвертирую ее в бесконечный цикл:
for(;;) recursiveFunction(oneParam);