web-dev-qa-db-ja.com

Cの完全な「for」ループ構文とは何ですか?

他の人のコードを読むときに、非常に奇妙なforループを見てきました。私はforCループの完全な構文の説明を検索しようとしましたが、単語「for」が無関係な文に表示されるため非常に困難ですGoogleにとって事実上不可能です。

this thread を読んだ後、この質問が思い浮かびました。

ここのfor

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

中間の条件では、2つのコードを区切るコンマがありますが、このコンマは何をしますか?右側のコンマは、a>>=1およびb<<=1

しかし、ループの終了条件内では、どうなりますか? p==0、 いつ a==1または両方が発生したとき?

誰かがこれを理解するのを手伝ってくれて、多分forループ構文の完全な説明の方向を教えてくれるといいですね。

59
fmsf

コンマはforループを除外しません。カンマ演算子です。

x = (a, b);

最初にa、次にbを実行し、次にxをbの値に設定します。

For構文は次のとおりです。

for (init; condition; increment)
    ...

これは、(今のところcontinuebreakを無視して)同等です:

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

あなたのforループの例は(再びcontinuebreakを無視して)と同等です

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

それはあたかもそうであるかのように振る舞います(再びcontinuebreakを無視)

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

上記のwhileループへの簡易変換ではなかったforループの2つの追加詳細:

  • 条件を省略すると、常にtrueになります(breakgoto、または他の何かがループを中断しない限り、無限ループになります)。
  • continueは、インクリメントをスキップするwhileループのcontinueとは異なり、インクリメントの直前のラベルへのgotoのように動作します。

また、コンマ演算子に関する重要な詳細:&&||のようなシーケンスポイントです(そのため、別のステートメントに分割してその意味を維持することができます)。


C99の変更

C99標準では、この説明の前半で言及されていないいくつかのニュアンスが導入されています(C89/C90に非常に適しています)。

まず、すべてのループはそれ自体がブロックです。事実上、

for (...) { ... }

それ自体が一対のブレースに包まれている

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

標準的なsayeth:

ISO/IEC 9899:1999§6.8.5反復ステートメント

¶5反復ステートメントは、そのスコープがそれを囲むブロックのスコープの厳密なサブセットであるブロックです。ループ本体も、スコープが反復ステートメントのスコープの厳密なサブセットであるブロックです。

これは、追加のブレースのセットの観点からも根拠に記載されています。

次に、C99のinit部分は、次のように(単一の)宣言になります。

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

ここで、「ループにラップされたブロック」は独自のものになります。変数iがループ外でアクセスできない理由を説明しています。複数の変数を宣言できますが、それらはすべて同じ型である必要があります。

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

標準的なsayeth:

ISO/IEC 9899:1999§6.8.5.3forステートメント

声明

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

式expression-2は、ループ本体の各実行前に評価される制御式です。式expression-3は、ループ本体が実行されるたびにvoid式として評価されます。 Clause-1が宣言の場合、宣言する変数のスコープは、宣言の残りと他の2つの式を含むループ全体です。制御式の最初の評価の前に、実行順に到達します。 Clause-1が式の場合、制御式の最初の評価の前にvoid式として評価されます。133)

第1節と第3節の両方を省略できます。省略されたexpression-2は、ゼロ以外の定数に置き換えられます。

133) したがって、clause-1はループの初期化を指定し、場合によってはループで使用する1つ以上の変数を宣言します。制御式expression-2は、各反復の前に行われる評価を指定し、式が0に等しくなるまでループの実行が継続されるようにします。 expression-3は、各反復後に実行される操作(増分など)を指定します。

131
CesarB

コンマは単純に2つの式を区切るだけで、通常の式が許可されるCのどこでも有効です。これらは左から右の順に実行されます。右端の式の値は、式全体の値です。

forループは3つの部分で構成され、そのいずれも空の場合もあります。各反復の最初に1つ(最初)が実行され、最後に1つ(3番目)が実行されます。これらの部分は通常、それぞれカウンターを初期化および増分します。しかし、彼らは何でもするかもしれません。

2番目の部分はtestで、各実行の開始時に実行されます。テストでfalseが生成された場合、ループは中止されます。これですべてです。

8
Konrad Rudolph

Cスタイルのループは、3つの式で構成されます。

for (initializer; condition; counter) statement_or_statement_block;
  • イニシャライザは、ループが開始されると1回実行されます。
  • 条件は各反復の前にチェックされます。ループは、trueと評価される限り実行されます。
  • カウンターは各反復後に1回実行されます。

これらの各部分は、ループを記述する言語で有効な式にすることができます。つまり、より創造的に使用できることを意味します。事前にしたいことはすべてイニシャライザーに入り、その間にやりたいことはすべて、ループがもはや本体を持たないところまで条件またはカウンターに入ることができます。

これを実現するには、カンマ演算子が非常に便利です。式を連結して、1つの新しい式を形成できます。ほとんどの場合、forループでそのように使用されますが、カンマ演算子のその他の意味(値の割り当てに関する考慮事項など)は小さな役割を果たします。

構文を創造的に使用することで巧妙なことを行うことができますが、実際に正当な理由が見つかるまでそれを避けます。 forループでコードゴルフをプレイすると、コードの読み取りと理解(および保守)が難しくなります。

ウィキペディアには、ニース forループに関する記事 もあります。

5
Tomalak

forループではすべてがオプションです。複数の変数を初期化したり、複数の条件を確認したり、カンマ演算子を使用して複数の変数を反復処理したりできます。

次のforループは、無限ループに入ります。状態を確認して注意してください。

for(;;) 
2
karthik

コンラッドは、繰り返したいキーポイントに言及しました:一番右の式の値は、式全体の値です。

Gnuコンパイラーは、forループの「条件」セクションに2つのテストを置いたときにこの警告を述べました。

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

私が「条件」に対して本当に意図したのは、間に「&&」を挿入した2つのテストでした。 Konradの声明によると、コンマの右側のテストのみが条件に影響します。

0
Bob