他の人のコードを読むときに、非常に奇妙なfor
ループを見てきました。私はfor
のC
ループの完全な構文の説明を検索しようとしましたが、単語「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
ループ構文の完全な説明の方向を教えてくれるといいですね。
コンマは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;
}
上記のwhileループへの簡易変換ではなかったforループの2つの追加詳細:
true
になります(break
、goto
、または他の何かがループを中断しない限り、無限ループになります)。continue
は、インクリメントをスキップするwhileループのcontinue
とは異なり、インクリメントの直前のラベルへのgotoのように動作します。また、コンマ演算子に関する重要な詳細:&&
や||
のようなシーケンスポイントです(そのため、別のステートメントに分割してその意味を維持することができます)。
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は、各反復後に実行される操作(増分など)を指定します。
コンマは単純に2つの式を区切るだけで、通常の式が許可されるCのどこでも有効です。これらは左から右の順に実行されます。右端の式の値は、式全体の値です。
for
ループは3つの部分で構成され、そのいずれも空の場合もあります。各反復の最初に1つ(最初)が実行され、最後に1つ(3番目)が実行されます。これらの部分は通常、それぞれカウンターを初期化および増分します。しかし、彼らは何でもするかもしれません。
2番目の部分はtestで、各実行の開始時に実行されます。テストでfalse
が生成された場合、ループは中止されます。これですべてです。
Cスタイルのループは、3つの式で構成されます。
for (initializer; condition; counter) statement_or_statement_block;
これらの各部分は、ループを記述する言語で有効な式にすることができます。つまり、より創造的に使用できることを意味します。事前にしたいことはすべてイニシャライザーに入り、その間にやりたいことはすべて、ループがもはや本体を持たないところまで条件またはカウンターに入ることができます。
これを実現するには、カンマ演算子が非常に便利です。式を連結して、1つの新しい式を形成できます。ほとんどの場合、forループでそのように使用されますが、カンマ演算子のその他の意味(値の割り当てに関する考慮事項など)は小さな役割を果たします。
構文を創造的に使用することで巧妙なことを行うことができますが、実際に正当な理由が見つかるまでそれを避けます。 forループでコードゴルフをプレイすると、コードの読み取りと理解(および保守)が難しくなります。
ウィキペディアには、ニース forループに関する記事 もあります。
for
ループではすべてがオプションです。複数の変数を初期化したり、複数の条件を確認したり、カンマ演算子を使用して複数の変数を反復処理したりできます。
次のfor
ループは、無限ループに入ります。状態を確認して注意してください。
for(;;)
コンラッドは、繰り返したいキーポイントに言及しました:一番右の式の値は、式全体の値です。
Gnuコンパイラーは、forループの「条件」セクションに2つのテストを置いたときにこの警告を述べました。
warning: left-hand operand of comma expression has no effect
私が「条件」に対して本当に意図したのは、間に「&&」を挿入した2つのテストでした。 Konradの声明によると、コンマの右側のテストのみが条件に影響します。