Я видел несколько очень странных циклов 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.
Исправлены некоторые ошибки. Пост теперь выглядит намного лучше. Интересный вопрос.





Запятая просто разделяет два выражения и действительна в любом месте C, где разрешено нормальное выражение. Они выполняются слева направо. Значение самого правого выражения - это значение всего выражения.
Циклы for состоят из трех частей, любая из которых также может быть пустой; одна (первая) выполняется в начале, а другая (третья) - в конце каждой итерации. Эти части обычно инициализируют и увеличивают счетчик соответственно; но они могут сделать что угодно.
Вторая часть - это тестовое задание, которая выполняется в начале каждого выполнения. Если тест дает false, цикл прерывается. Это все, что нужно сделать.
То, как вы сформулировали свое предложение «одна (первая) выполняется в начале, а одна (третья) в конце каждой итерации», может заставить некоторых людей подумать, что первая часть выполняется в начале каждой итерации.
Запятая не исключает циклы 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 вводит несколько нюансов, не упомянутых ранее в этом объяснении (что очень хорошо для C89 / C90).
Во-первых, все петли сами по себе являются блоками. Фактически,
for (...) { ... }
сам завернут в скобки
{
for (...) { ... }
}
Стандарт гласит:
ISO/IEC 9899:1999 §6.8.5 Iteration statements
¶5 An iteration statement is a block whose scope is a strict subset of the scope of its enclosing block. The loop body is also a block whose scope is a strict subset of the scope of the iteration statement.
Это также описано в Обосновании с точки зрения дополнительного набора скоб.
Во-вторых, часть 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 The for statement
The statement
for ( clause-1 ; expression-2 ; expression-3 ) statementbehaves as follows: The expression expression-2 is the controlling expression that is evaluated before each execution of the loop body. The expression expression-3 is evaluated as a void expression after each execution of the loop body. If clause-1 is a declaration, the scope of any variables it declares is the remainder of the declaration and the entire loop, including the other two expressions; it is reached in the order of execution before the first evaluation of the controlling expression. If clause-1 is an expression, it is evaluated as a void expression before the first evaluation of the controlling expression.133)
Both clause-1 and expression-3 can be omitted. An omitted expression-2 is replaced by a nonzero constant.
133) Thus, clause-1 specifies initialization for the loop, possibly declaring one or more variables for use in the loop; the controlling expression, expression-2, specifies an evaluation made before each iteration, such that execution of the loop continues until the expression compares equal to 0; and expression-3 specifies an operation (such as incrementing) that is performed after each iteration.
В языке C запятая имеет более низкий приоритет, чем присвоение, поэтому «x = a, b;» сначала установит x в a, затем сделает b.
@DavidThornley, что, если бы это было x = a, b; а не (а, б)?
@TM: если я правильно понял, «x = a, b» присвоит a переменной x, затем вычислит b и отбросит его значение.
Цикл for в стиле C состоит из трех выражений:
for (initializer; condition; counter) statement_or_statement_block;
Каждая из этих частей может быть выражением, действительным на языке, на котором вы пишете цикл. Это означает, что их можно использовать более творчески. Все, что вы хотите сделать заранее, может быть передано в инициализатор, все, что вы хотите сделать между ними, может перейти в условие или счетчик, вплоть до того момента, когда цикл больше не имеет тела.
Для этого очень удобен оператор запятой. Он позволяет связывать выражения вместе, чтобы сформировать одно новое выражение. В большинстве случаев он используется таким образом в цикле for, другие значения оператора запятой (например, соображения присвоения значений) играют второстепенную роль.
Даже несмотря на то, что вы можете делать умные вещи, творчески используя синтаксис, я бы держался от него подальше, пока не найду для этого вескую причину В самом деле. Игра в кодовый гольф с циклами for затрудняет чтение и понимание (и сопровождение) кода.
В википедии тоже есть хороший статья о цикле for.
Разрешен ли еще один цикл for в разделе counter, который позволит определять вложенные циклы for в том же операторе? Другими словами, как составной цикл for определяется в C / C++?
Я недостаточно специалист по языку Си, чтобы ответить на этот вопрос. Тем не менее интересный и оригинальный вопрос. Есть хороший шанс получить ответ, если вы зададите этот актуальный вопрос здесь.
И я последовал твоему совету, вот отвечать. И, пожалуйста, проголосуйте за вопрос, если вы так считаете. Наслаждаться!
В цикле for все необязательно. Мы можем инициализировать более одной переменной, мы можем проверить более одного условия, мы можем выполнить итерацию более чем одной переменной, используя оператор запятой.
Следующий цикл for перенесет вас в бесконечный цикл. Будьте осторожны, проверяя состояние.
for(;;)
Просто впервые увидел это в старом коде C 90-х годов, выходя с "goto", серьезно ??
Конрад упомянул ключевой момент, который я хотел бы повторить: значение самого правого выражения - это значение всего выражения.
Компилятор Gnu сообщил об этом предупреждении, когда я поместил два теста в раздел «условие» цикла for.
warning: left-hand operand of comma expression has no effect
На самом деле я имел в виду два теста с символом «&&» между ними. По утверждению Конрада, только тест справа от запятой повлияет на состояние.
что вы имеете в виду под «значением крайнего правого выражения - значением overall expression.»? Я полагаю, вы имеете в виду: «Значение крайнего правого выражения - это значение всего comma expression»?
цикл for выполняется в течение определенного времени для (;;)
синтекс для цикла
для(;;)
ИЛИ ЖЕ
for (инициализатор; условие; счетчик)
например (rmv = 1; rmv <= 15; rmv ++)
выполнение до 15 раз за блок
1. сначала инициализируйте значение, потому что начните значение
(например) rmv = 1 или rmv = 2
2. второй оператор проверяет, является ли условие истинным или ложным, истинным условием является количество времени выполнения цикла for и условие ложно завершение для блока,
например, я = 5; я <= 10 условие истинно
i=10;i<10 the condition is false terminate for block,
3. третья - увеличение или уменьшение
(например) rmv ++ или ++ rmv
У вас ужасное форматирование. Вы должны писать код в моноширинном формате. Чтобы создать блок кода, сделайте отступ для каждой принадлежащей ему строки, используя 4 пробела. Чтобы сделать такой inline monospace, используйте `в начале и в конце текста, который вы хотите моноширинный.
Кроме того, for(;;) не является альтернативным синтаксисом; это нормальный синтаксис с пропущенными инициализатором, условием и счетчиком.
@Jesus - Вы исправили "kinda" на "kind of", "coma" to "comma", написали "I" и "Does" с заглавной буквы, но оставили "ppl" для людей?