C中的递归深度是不是有任何硬连线限制
Posted
技术标签:
【中文标题】C中的递归深度是不是有任何硬连线限制【英文标题】:Is there any hard-wired limit on recursion depth in CC中的递归深度是否有任何硬连线限制 【发布时间】:2012-05-01 20:08:07 【问题描述】:正在讨论的程序尝试使用recursion
计算sum-of-first-n-natural-numbers
。我知道这可以使用一个简单的公式n*(n+1)/2
来完成,但这里的想法是使用recursion
。
程序如下:
#include <stdio.h>
unsigned long int add(unsigned long int n)
return (n == 0) ? 0 : n + add(n-1);
int main()
printf("result : %lu \n", add(1000000));
return 0;
该程序对n = 100,000
运行良好,但是当n
的值增加到1,000,000
时,它会导致Segmentation fault (core dumped)
以下内容来自gdb
消息。
Program received signal SIGSEGV, Segmentation fault.
0x00000000004004cc in add (n=Cannot access memory at address 0x7fffff7feff8
) at k.c:4
我的问题:
C
中的recursion depth
是否有任何硬接线限制?还是recursion depth
取决于可用的堆栈内存?
程序收到 reSIGSEGV 信号的可能原因有哪些?
【问题讨论】:
两个问题,请发两个问题。问题 1 可能重复 ***.com/q/2630054/1025391 【参考方案1】:C 中的递归深度没有理论上的限制。唯一的限制是您的实现,通常是有限的堆栈空间。 (请注意,C 标准实际上并不需要基于堆栈的实现。我不知道任何不基于堆栈的实际实现,但请记住这一点。)
SIGSEGV 可能由多种原因引起,但超出堆栈限制是一种相对常见的情况。取消引用坏指针是另一回事。
【讨论】:
【参考方案2】:通常限制是堆栈的大小。每次调用函数时,都会吃掉一定数量的堆栈(通常取决于函数)。吃掉的量就是栈帧,函数返回时回收。当程序启动时,堆栈大小几乎是固定的,要么是由操作系统指定(并且通常可以在那里调整),要么是在程序中硬编码。
某些实现可能有一种技术,可以在运行时分配新的堆栈段。但总的来说,他们不会。
一些函数会以稍微更不可预测的方式消耗堆栈,例如当它们在那里分配一个可变长度数组时。
某些函数可能被编译为使用尾调用,以保留堆栈空间。有时您可以重写您的函数,以便所有调用(例如对自身的调用)作为它所做的最后一件事发生,并期望您的编译器对其进行优化。
要准确看出每次调用函数需要多少堆栈空间并不是那么容易,这将取决于编译器的优化级别。在您的情况下,一种便宜的方法是在每次调用时打印&n
; n
可能在堆栈上(特别是因为程序需要获取它的地址——否则它可能在寄存器中),它的连续位置之间的距离将指示堆栈帧的大小。
【讨论】:
“程序启动时堆栈大小几乎是固定的” - 或者创建线程时,对于除第一个线程之外的任何线程。【参考方案3】:C 标准没有定义函数调用的最小支持深度。如果确实如此,无论如何都很难保证,它会在5.2.4 Environmental limits
部分的某个地方提到它。
【讨论】:
什么文件的第 5.2.4 节?! 如果你把网址加了书签,你能分享一下吗!?谢谢!【参考方案4】:1)预计栈的消耗会减少,写成尾递归优化。
gcc -O3 prog.c
#include <stdio.h>
unsigned long long int add(unsigned long int n, unsigned long long int sum)
return (n == 0) ? sum : add(n-1, n+sum); //tail recursion form
int main()
printf("result : %llu \n", add(1000000, 0));//OK
return 0;
【讨论】:
以上是关于C中的递归深度是不是有任何硬连线限制的主要内容,如果未能解决你的问题,请参考以下文章