嵌套的for循环的数量是否有限制?
由于一切都有限制,我想知道是否有嵌套for
循环的数量的限制或只要我有内存,我可以添加它们,Visual Studio编译器可以创build这样一个程序?
当然64个或更多的嵌套for
循环将不方便debugging,但它是可行的吗?
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中的默认设置
我创build了一个小程序,生成嵌套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”抛出一个types为“System.InsufficientExecutionStackException”的exception,消息“栈不足以继续安全地执行程序。 这可能是由于调用堆栈上的函数过多或堆栈空间太多而导致的。
与底层的编译器消息
错误CS8078:expression式太长或编译复杂
当然,这是纯粹的假设结果。 如果最内层的循环比Console.WriteLine
,那么在超过堆栈大小之前,可能会有更less的嵌套循环。 此外,这可能不是一个严格的技术限制,因为可能存在隐藏设置,以增加错误消息中提到的“分析器”的最大堆栈大小,或者(如果需要)生成可执行文件。 然而,这部分答案留给了深入了解C#的人。
更新
针对评论中的问题 :
我有兴趣看到这个答案扩大到“实validation明”,如果你不能在for循环中使用575个局部variables,或者你可以把575个非嵌套的 for循环放入一个单一的function
对于这两种情况,答案是:是的,这是可能的。 用575个自动生成的语句填充该方法
int i0=0; Console.WriteLine(i0); int i1=0; Console.WriteLine(i1); ... int i574=0; Console.WriteLine(i574);
它仍然可以编译。 其他一切都会让我感到惊讶。 int
variables所需的堆栈大小仅为2.3 KB。 但我很好奇,为了testing更多的限制,我增加了这个数字。 最终,它没有编译,导致错误
错误CS0204:只允许65534个当地人,包括由编译器生成的当地人
这是一个有趣的点,但已经在其他地方观察到: 方法中variables的最大数量
同样,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); }
也可以编译。 在这里,我也试图find限制,并创造更多的这些循环。 特别是,我不确定在这种情况下,循环variables是否也算“als”locals,因为它们在它们自己的{ block }
。 但仍然超过65534个是不可能的。 最后,我添加了一个由40000个模式循环组成的testing
for (int i39999 = 0; i39999 < 10; i39999++) { int j = 0; Console.WriteLine(j + i39999); }
在循环中包含一个额外的variables,但这些似乎也算作“本地人”,而且这是不可能的。
所以总结一下:〜550的极限确实是由环路的嵌套深度造成的。 这也是由错误信息指示的
错误CS8078:expression式太长或编译复杂
不幸的是(但是可以理解的) 错误CS1647的文档没有指定复杂度的“度量”,而只是给出了实用的build议
编译器处理你的代码时有一个堆栈溢出。 要解决此错误,请简化您的代码。
再次强调这一点: 对于深层嵌套的特定情况,这一切都是相当学术和假设的 。 但是,对CS1647的错误信息进行networkingsearch会发现几种情况,这种错误出现在最有可能不是故意复杂的代码中,而是在现实场景中创build的。
C#语言规范或CLR没有硬性限制。 你的代码是迭代的,而不是recursion的,这可能导致堆栈溢出相当快。
有几件事情可以作为一个门槛,例如(一般) int
计数器,你会使用,这将分配在每个循环的内存中的int
(和之前,你已经分配你的整个堆栈… …)。 请注意,使用该int
是必需的,您可以重用相同的variables。
正如Marco所指出的那样,编译器中的当前阈值大于实际语言规范或运行时。 一旦被重新编码,你可能会有更多的迭代。 例如 , 如果使用Ideone ,默认情况下使用旧的编译器,则可以轻松地获得超过1200个for
循环。
尽pipe如此,循环是糟糕的devise指标。 我希望这个问题纯粹是假设的。
所有编译到MSIL的C#都有一个限制。 MSIL只能支持65535个局部variables。 如果for
循环与您在示例中显示的循环相同,则每个循环都需要一个variables。
你的编译器可能会在堆上分配对象来充当局部variables的存储,从而绕过这个限制。 但是,我不确定会有什么奇怪的结果。 反思可能会产生一些问题,使得这种做法非法。
在800和900之间for(;;)
循环清空。
反映Marco13的方法,除了尝试for(;;)
循环:
for (;;) // 0 for (;;) // 1 for (;;) // 2 // ... for (;;) // n_max { // empty body }
它适用for(;;)
嵌套800,但它给了Marco13尝试900循环时遇到的相同的错误。
当它编译时, for(;;)
似乎阻塞线程而不会使CPU最大化; 表面上,它似乎像一个Thread.Sleep()
。