1. ホーム
  2. c#

[解決済み] ネストされた'for'ループの数に限界はありますか?

2023-07-06 01:09:20

質問

何事にも限度がありますから、ネストされた for ループの数に制限があるのか、それともメモリさえあれば追加できるのか、Visual Studioコンパイラはそのようなプログラムを作成できるのでしょうか?

もちろん、64以上のネストされた for ループはデバッグに便利ではありませんが、それは可能でしょうか?

private void TestForLoop()
{
  for (int a = 0; a < 4; a++)
  {
    for (int b = 0; b < 56; b++)
    {
      for (int c = 0; c < 196; c++)
      {
        //etc....
      }
    }
  }
}

どのように解決するのですか?

思い切って投稿してみましたが、その答えは

550と575の間

Visual Studio 2015 のデフォルト設定による

私は、ネストされた for のループを生成する小さなプログラムを作りました...

for (int i0=0; i0<10; i0++)
{
    for (int i1=0; i1<10; i1++)
    {
        ...
        ...
        for (int i573=0; i573<10; i573++)
        {
            for (int i574=0; i574<10; i574++)
            {
                Console.WriteLine(i574);
            }
        }
        ...
        ...
    }
}

500回のネストされたループの場合、プログラムはまだコンパイル可能です。575ループの場合、コンパイラはベイルアウトします。

警告 AD0001 Analyzer 'Microsoft.CodeAnalysis.CSharp.Diagnostics.SimplifyTypeNames.CSharpSimplifyTypeNamesDiagnosticAnalyzer' はメッセージ 'InsufficientStackException' タイプの例外を投げました 'プログラムを安全に実行し続けるための十分なスタックがありません' と書いてあります。これは、コールスタック上にあまりにも多くの関数があるか、スタック上の関数があまりにも多くのスタックスペースを使用している場合に発生する可能性があります'。

というコンパイラーメッセージが表示されます。

<ブロッククオート

error CS8078: 式が長すぎるか複雑すぎるため、コンパイルできません。

もちろん、これは 純粋に仮説であり の結果です。もし一番内側のループが Console.WriteLine を行う場合、スタックサイズを超える前に可能なネストされたループの数は少なくなるかもしれません。また、これは厳密には技術的な制限ではないかもしれません。エラーメッセージで言及されている "Analyzer"、または(必要に応じて)結果の実行可能ファイルの最大スタックサイズを増やすための隠れた設定があるかもしれないという意味でもです。しかし、この部分の回答は、C# を深く知っている人に任されています。


アップデート

に対する対応として の質問に対して :

この回答を拡大して、575個のローカル変数をスタック上に置くことができるかどうかを実験的に証明することに興味があります。 ではない でない場合、575 個のローカル変数をスタックに置くことができるかどうか、および/または、575個の ネストされていない を一つの関数に入れることができるかどうか。

どちらのケースでも、答えは「はい、可能です」です。メソッドに575の自動生成ステートメントを記入する場合

int i0=0;
Console.WriteLine(i0);
int i1=0;
Console.WriteLine(i1);
...
int i574=0;
Console.WriteLine(i574);

であれば、まだコンパイル可能です。それ以外のことは驚きの連続だったでしょう。必要なスタックサイズは int 変数に必要なスタックサイズは、わずか2.3KBです。しかし、私は好奇心旺盛で、さらなる限界を試すために、この数字を増やしました。最終的に、それは ではなく がコンパイルされ、エラーが発生しました。

エラーCS0204。コンパイラが生成したものを含め、65534個のローカルしか許可されません

というのは興味深い点ですが、すでに他の場所で観察されています。 メソッド内の変数の最大数

同様に、575 ネストされていない for のような-loopがあります。

for (int i0=0; i0<10; i0++)
{
    Console.WriteLine(i0);
}
for (int i1=0; i1<10; i1++)
{
    Console.WriteLine(i1);
}
...
for (int i574=0; i574<10; i574++)
{
    Console.WriteLine(i574);
}

も同様にコンパイルすることができる。ここでは、その限界を探るために、さらにこのループを作成しました。特に、この場合のループの変数は、自分自身の { block } . しかし、それでも65534以上はありえません。最後に、私はパターンの40000ループからなるテストを追加しました。

for (int i39999 = 0; i39999 < 10; i39999++)
{
    int j = 0;
    Console.WriteLine(j + i39999);
}

は、追加の変数 を含んでいますが、これらも同様に "locals" としてカウントされるようで、これをコンパイルすることはできませんでした。


ということで、まとめます。550 という限界は、確かに ネストの深さ が原因です。これはまた、エラーメッセージによって示されました

error CS8078: 式が長すぎるか複雑すぎるため、コンパイルできません。

その エラー CS1647 のドキュメント 残念ながら (しかし当然ながら)、複雑さの測定は指定されておらず、実用的なアドバイスが与えられているだけです。

あなたのコードを処理するコンパイラでスタックオーバーフローが発生しました。このエラーを解決するには、コードを簡略化してください。

これを再度強調するために を深くネストした特殊なケースについては for -ループの場合、このすべてはむしろ学術的で仮説的なものです。 . しかし、CS1647 のエラー メッセージを Web で検索すると、おそらく意図的に複雑なものではなく、現実的なシナリオで作成されたコードにこのエラーが表示されるケースがいくつか見つかります。