【问题标题】: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

我的问题:

  1. C 中的recursion depth 是否有任何硬接线限制?还是recursion depth 取决于可用的堆栈内存?

  2. 程序收到 reSIGSEGV 信号的可能原因有哪些?

【问题讨论】:

标签: c recursion stack segmentation-fault


【解决方案1】:

C 中的递归深度没有理论上的限制。唯一的限制是您的实现,通常是有限的堆栈空间。
(请注意,C 标准实际上并不需要基于堆栈的实现。我不知道任何不基于堆栈的实际实现,但请记住这一点。)

SIGSEGV 可能由多种原因引起,但超出堆栈限制是一种相对常见的情况。取消引用坏指针是另一回事。

【讨论】:

    【解决方案2】:

    通常限制是堆栈的大小。每次调用函数时,都会吃掉一定数量的堆栈(通常取决于函数)。吃掉的量就是栈帧,函数返回时回收。当程序启动时,堆栈大小几乎是固定的,要么是由操作系统指定(并且通常可以在那里调整),要么是在程序中硬编码。

    • 某些实现可能有一种技术,可以在运行时分配新的堆栈段。但总的来说,他们不会。

    • 一些函数会以稍微更不可预测的方式消耗堆栈,例如当它们在那里分配一个可变长度数组时。

    • 某些函数可能被编译为使用尾调用,以保留堆栈空间。有时您可以重写您的函数,以便所有调用(例如对自身的调用)作为它所做的最后一件事发生,并期望您的编译器对其进行优化。

    要准确看出每次调用函数需要多少堆栈空间并不是那么容易,这将取决于编译器的优化级别。在您的情况下,一种便宜的方法是在每次调用时打印&amp;nn 可能在堆栈上(特别是因为程序需要获取它的地址——否则它可能在寄存器中),它的连续位置之间的距离将指示堆栈帧的大小。

    【讨论】:

    • “程序启动时堆栈大小几乎是固定的” - 或者创建线程时,对于除第一个线程之外的任何线程。
    【解决方案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;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-02-07
      • 1970-01-01
      • 2020-08-06
      • 1970-01-01
      • 2012-10-26
      • 2016-03-02
      • 1970-01-01
      • 1970-01-01
      • 2011-05-29
      相关资源
      最近更新 更多