未承認ループが多すぎると、Visual C++ で C1061 コンパイラ エラーが発生する

この記事は、C++ ソース ファイルとして関数に 250 を超える未更新ループを含むソース コードをコンパイルするときに発生する C1061 コンパイラ エラーを解決するのに役立ちます。

元の製品バージョン: Visual Studio Premium 2012、Visual Studio 2010
元の KB 番号: 315481

現象

関数に約 250 個を超える未更新ループが含まれている場合は、このシナリオでは表示されない次のエラー メッセージが表示されます。

致命的なエラー C1061: コンパイラの制限: 入れ子になりすぎるブロック

この問題は、ソース コードを C++ ソース ファイルとしてコンパイルする場合にのみ発生します。 ソース コードは、C ソース ファイルとしてコンパイルするときにエラーなしでコンパイルされます。

回避策

各 for ループを中かっこで囲み、囲むスコープを作成します。

{
    for (i=0; i<5; i++)
    {
        a += a*i;
    }
}

動作の再現手順

次のサンプル コードは、エラーを示しています。

/* Compile options needed: /TP /c
*/
#include <stdio.h>

// The code blocks in this function have only two nesting levels.
// C1061 should not occur.
void func1()
{
    int a;
    int i = 0;
    int count = 0;

    count++;
    a = count;
    for (i=0; i<5; i++)
    {
        a += a*i;
    }
    printf("a=%d\n", a);

    // Copy and paste the following code 250 times.
    /*
    for (i=0; i<5; i++)
    {
        a += a*i;
    }
    printf("a=%d\n", a);
    */

    count++;
    a = count;
    for (i=0; i<5; i++)
    {
        a += a*i;
    }
    printf("a=%d\n", a);
}

void main()
{
    func1();
}

詳細

/Zc:forScope が有効になっているときに警告 C4258 を発行するには、C++ コンパイラが同じスコープ内のすべての for ループを追跡する必要があります。

int i;
void foo()
{
    for (int i = 0; i < 10; ++i)
    {
        if (i == 5) break;
    }
    if (i == 5)... // C4258: this 'i' comes from an outer scope, not the for-loop
}

/Zc:ForScope を無効にすると、iコメントされた行の代わりに for ループから取得されます。 この動作の違いをユーザーに通知する必要があります。

残念ながら、スコープは単純ではないデータ構造であるため、コンパイラは同時に追跡できるスコープの数に制限があるため、ここで説明するバグが発生します。

この回避策では、各 for ループを分離して、他の for ループと同じスコープにならないようにすることでこの問題を解決します。これにより、コンパイラのすべてのスコープを同時に追跡する必要がなくなります。 回避策を見るもう 1 つの方法は、余分な囲みスコープ外で警告 C4258 が発生する可能性を回避することです。

int i;
void foo()
{
    {
        for (int i = 0; i < 10; ++i)
        {
            if (i == 5) break;
        }
    }
    if (i == 5)...
    // this 'i' comes from the outer scope regardless of whether /Zc:forScope is enabled
}