Вопрос

Я видел некоторые очень странные for циклы при чтении чужого кода.Я пытался найти полное объяснение синтаксиса для for зациклиться C но это очень тяжело, потому что слово "for" появляется в несвязанных между собой предложениях, что делает эффективный поиск для Google практически невозможным.

Этот вопрос пришел мне в голову после прочтения эта тема что снова вызвало у меня любопытство.

А for здесь:

for(p=0;p+=(a&1)*b,a!=1;a>>=1,b<<=1);

В среднем условии есть запятая, разделяющая два фрагмента кода. Что делает эта запятая?Я понимаю запятую справа, поскольку она делает и то, и другое. a>>=1 и b<<=1.

Но что происходит в условиях выхода из цикла?Выходит ли он, когда p==0, когда a==1 или когда произойдет и то, и другое?

Было бы здорово, если бы кто-нибудь помог мне понять это и, возможно, указал мне направление полного for описание синтаксиса цикла.

Это было полезно?

Решение

Запятая не исключает циклов for;это оператор запятая.

x = (a, b);

сначала выполнит a, затем b, а затем присвоит x значение b.

Синтаксис for:

for (init; condition; increment)
    ...

Что в некоторой степени (игнорируя continue и break на данный момент) эквивалентно:

init;
while (condition) {
    ...
    increment;
}

Итак, ваш пример цикла for (опять игнорируя continue и break) эквивалентно

p=0;
while (p+=(a&1)*b,a!=1) {
    ...
    a>>=1,b<<=1;
}

Который действует так, как если бы это было (опять игнорируя continue и break):

p=0; 
while (true) {
    p+=(a&1)*b;
    if (a == 1) break;
    ...
    a>>=1;
    b<<=1;
}

Две дополнительные детали цикла for, которых не было в приведенном выше упрощенном преобразовании в цикл while:

  • Если условие опущено, оно всегда true (что приводит к бесконечному циклу, если только break, goto, или что-то еще разрывает цикл).
  • А continue действует так, как если бы это был переход к метке непосредственно перед приращением, в отличие от continue в цикле while, который пропустит приращение.

Также важная деталь об операторе запятая:это точка последовательности, например && и || (именно поэтому я могу разделить его на отдельные утверждения и сохранить его смысл нетронутым).


Изменения в C99

Стандарт C99 вводит пару нюансов, не упомянутых ранее в этом пояснении (что очень хорошо для C89/C90).

Во-первых, все циклы сами по себе являются блоками.Эффективно,

for (...) { ... }

сам заключен в пару фигурных скобок

{
for (...) { ... }
}

Стандарт гласит:

ISO/IEC 9899:1999 §6.8.5 Операторы итерации

¶5. Заявление итерации - это блок, сфера которой является строгое подмножество объема его блока.Корпус петли также является блоком, сфера которой является строгое подмножество объема операции итерации.

Это также описано в «Обосновании» с точки зрения дополнительного набора скобок.

Во-вторых, init часть в C99 может быть (единственным) объявлением, как в

for (int i = 0; i < sizeof(something); i++) { ... }

Теперь «блок, обернутый вокруг цикла», вступает в свои права;это объясняет, почему переменная i доступ к нему вне цикла невозможен.Вы можете объявить более одной переменной, но все они должны быть одного типа:

for (int i = 0, j = sizeof(something); i < j; i++, j--) { ... }

Стандарт гласит:

ISO/IEC 9899:1999 §6.8.5.3 Оператор for

Заявление

for ( clause-1 ; expression-2 ; expression-3 ) statement

ведет себя следующим образом:Экспрессия экспрессии-2-это контролирующая экспрессия, которая оценивается до каждого выполнения тела петли.Экспрессия экспрессии-3 оценивается как пустое экспрессия после каждого выполнения тела петли.Если пункт-1 является объявлением, объем любых переменных, которые он заявляет, является оставшейся частью объявления и всего цикла, включая два других выражения;Это достигается в порядке выполнения до первой оценки контролирующего выражения.Если пункт-1 является выражением, он оценивается как пустое выражение перед первой оценкой контрольной экспрессии.133)

И пункт 1, и выражение 3 можно опустить.Пропущенное выражение-2 заменяется ненулевой постоянной.

133) Таким образом, CLAUE-1 указывает инициализацию для цикла, возможно, объявляя одну или несколько переменных для использования в цикле;Контролирующая экспрессия, экспрессия-2, определяет оценку, проведенную перед каждой итерацией, так что выполнение цикла продолжается до тех пор, пока выражение не сравнится с равным 0;и Expression-3 указывает операцию (такую ​​как увеличение), которая выполняется после каждой итерации.

Другие советы

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

Циклы

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

Вторая часть - это тест , который выполняется в начале каждого выполнения. Если тест выдает false , цикл прерывается. Вот и все, что нужно сделать.

Цикл for в стиле C состоит из трех выражений:

for (initializer; condition; counter) statement_or_statement_block;
  • Инициализатор запускается один раз при запуске цикла.
  • Условие проверяется перед каждой итерацией.Цикл выполняется до тех пор, пока его значение истинно.
  • Счетчик запускается один раз после каждой итерации.

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

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

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

В Википедии есть хорошая статья о цикле for также.

В цикле for все необязательно. Мы можем инициализировать более одной переменной, мы можем проверить более одного условия, мы можем перебрать более одной переменной, используя оператор запятой.

Следующий цикл for приведет вас к бесконечному циклу. Будьте осторожны, проверяя состояние.

for(;;) 

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

Компилятор Gnu объявил об этом предупреждении, когда я поместил два теста в "условие" раздел цикла for

warning: left-hand operand of comma expression has no effect

Что я на самом деле намеревался для "условия"? было два теста с & amp; & amp; " между. Согласно утверждению Конрада, только условие справа от запятой может повлиять на состояние.

цикл for выполняется в течение определенного времени for(;;)

синтаксис цикла for

для(;;)

ИЛИ

для (инициализатор;состояние;прилавок)

например (rmv=1;rmv<=15;rmv++)

выполнение до 15 раз за блок

1. сначала инициализируйте значение, потому что запустите значение

(например)rmv=1 или rmv=2

2.Второй оператор проверяет, условие истинно или ложно, условие истинно, время выполнения цикла for и условие ложно, завершает блок,

например, i=5;i<=10, условие истинно

i=10;i<10 the condition is false terminate for block,

3.третий — увеличение или уменьшение

(например)rmv++ или ++rmv

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top