[c#] 중첩 된 ‘for’루프의 수에 제한이 있습니까?

모든 것이 제한이 있기 때문에 중첩 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 분석기 ‘Microsoft.CodeAnalysis.CSharp.Diagnostics.SimplifyTypeNames.CSharpSimplifyTypeNamesDiagnosticAnalyzer’에서 ‘프로그램을 안전하게 계속 실행하기위한 스택 부족’메시지와 함께 ‘System.InsufficientExecutionStackException’유형의 예외가 발생했습니다. 이것은 호출 스택에 너무 많은 함수를 가지고 있거나 너무 많은 스택 공간을 사용하는 스택에 함수를 가지고 있기 때문에 발생할 수 있습니다. ‘.

기본 컴파일러 메시지

오류 CS8078 :식이 너무 길거나 복잡하여 컴파일 할 수 없습니다.

물론 이것은 순전히 가설적인 결과입니다. 가장 안쪽에있는 루프가 Console.WriteLine. 또한 이는 오류 메시지에 언급 된 “분석기”의 최대 스택 크기를 늘리거나 결과 실행 파일에 대해 (필요한 경우) 숨겨진 설정이있을 수 있다는 점에서 엄격한 기술 제한이 아닐 수도 있습니다. 그러나 대답의이 부분은 C #을 깊이 알고있는 사람들에게 맡겨져 있습니다.


최신 정보

댓글질문에 대한 답변 :

이 답변이 확장 되어 for 루프에서 사용 되지 않는 경우 스택에 575 개의 로컬 변수를 넣을 수 있는지 여부 및 / 또는 575 개의 비 중첩 for 루프를 넣을 수 있는지 여부를 실험적으로 “증명”하는 것을보고 싶습니다 . 단일 기능

두 경우 모두 대답은 다음과 같습니다. 예, 가능합니다. 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 루프

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);
}

컴파일 할 수도 있습니다. 여기서도 한계를 찾으려고 노력했고 이러한 루프를 더 많이 만들었습니다. 특히,이 경우 루프 변수가 자체적으로 존재하기 때문에 “locals”도 계산하는지 여부를 확신 할 수 없었습니다 { block }. 그러나 여전히 65534 이상은 불가능합니다. 마지막으로 40000 개의 패턴 루프로 구성된 테스트를 추가했습니다.

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

즉, 추가 변수 포함 에서 루프를하지만, 이러한뿐만 아니라 “지역 주민”으로 간주하는 것, 그리고이 컴파일 할 수 없었습니다.


요약하자면 ~ 550의 한계는 실제로 루프 의 중첩 깊이 로 인해 발생합니다 . 이것은 또한 오류 메시지로 표시되었습니다.

오류 CS8078 :식이 너무 길거나 복잡하여 컴파일 할 수 없습니다.

오류 CS1647에 대한 문서는 불행히도 (이해할 만하게도 ) 복잡성의 “측정”을 지정하지 않고 실용적인 조언 만 제공합니다.

코드를 처리하는 컴파일러에 스택 오버플로가 있습니다. 이 오류를 해결하려면 코드를 단순화하십시오.

이것을 다시 강조하기 위해 : 깊게 중첩 된 for루프 의 특별한 경우 에이 모든 것은 다소 학문적이고 가설 적 입니다. 그러나 CS1647의 오류 메시지에 대한 웹 검색을 통해이 오류가 의도적으로 복잡하지는 않지만 실제 시나리오에서 생성 된 코드에 대해 나타나는 몇 가지 경우를 알 수 있습니다.


답변

C # 언어 사양 또는 CLR에는 엄격한 제한이 없습니다. 코드는 재귀 적이기보다는 반복적이기 때문에 스택 오버플로가 매우 빠르게 발생할 수 있습니다.

임계 값으로 계산할 수있는 몇 가지 항목이 있습니다. 예를 들어 (일반적으로) 사용하는 int카운터 int는 각 루프에 대해 메모리 내를 할당합니다 (그리고 int로 전체 스택을 할당하기 전에 …). 이를 사용해야 int하며 동일한 변수를 재사용 할 수 있습니다.

마르코 지적 , 현재의 임계 값은 실제 언어 사양 또는 런타임에 비해 컴파일러에서 더 많은 것이다. 다시 코딩되면 훨씬 더 많은 반복 작업을 수행 할 수 있습니다. 예를 들어 기본적으로 이전 컴파일러를 사용하는 Ideone을 사용하면 1200 개 이상의 for루프를 쉽게 얻을 수 있습니다.

하지만 많은 for 루프는 잘못된 디자인의 지표입니다. 이 질문이 순전히 가설 적이기를 바랍니다.


답변

MSIL로 컴파일 된 모든 C #에는 제한이 있습니다. MSIL은 65535 지역 변수 만 지원할 수 있습니다. for루프가 예제에서 보여준 것과 같으면 각 루프에는 변수가 필요합니다.

컴파일러가 힙에 개체를 할당하여 로컬 변수의 저장소 역할을하여이 제한을 피할 수 있습니다. 그러나 나는 그것에서 어떤 종류의 이상한 결과가 나올지 잘 모르겠습니다. 그러한 접근을 불법으로 만드는 반성에서 발생하는 문제가있을 수 있습니다.


답변

for(;;)루프의 경우 800에서 900 사이 .

시도 된 for(;;)루프를 제외하고 미러링 된 Marco13의 접근 방식 :

for (;;)  // 0
for (;;)  // 1
for (;;)  // 2
// ...
for (;;)  // n_max
{
  // empty body
}

800 nested for(;;)에서 작동했지만 Marco13이 900 루프를 시도 할 때 발생한 것과 동일한 오류가 발생했습니다.

컴파일 할 때 for(;;)CPU를 최대로 사용하지 않고 스레드를 차단하는 것처럼 보입니다. 표면적으로는 Thread.Sleep().


답변