C语言之尾递归

这篇博客探讨了尾递归与线性递归的区别,指出尾递归在效率和资源消耗上的优势。通过示例展示了计算阶乘的两种递归实现,解释了尾递归如何避免栈空间的持续增长。同时,博主分享了在gcc 4.3.2编译器中,未优化和优化(-O3)后的尾递归函数汇编代码,进一步说明了编译器如何处理尾递归。
摘要由CSDN通过智能技术生成

昨天被问到了尾递归及编译器对它的处理相关,一直对它没有研究过,解释得很含糊。
回来查了下,记录如下:

递归有线性递归(普通的递归)和尾递归。
由于尾递归的特殊性,一般的编译器会做些特殊处理。因此,在效率和开销上,比普通递归好。
举个例子,计算n!
1)线性递归:
type recurve(long n)
{
      return  (n == 1) ? 1 : n * recurve(n - 1);
}
2)尾递归:
type recurve_tail(long n, long result)
{
          return (n == 1) ? result : recurve_tail(n - 1, result * n);  
}
再封装成1)的形式:
type recurve(long n)
{
    return (n == 0) ? 1 : recurve_tail(n, 1);
}

分析:
很容易看出, 普通的线性递归比尾递归更加消耗资源。每次调用都使得调用链条不断加长,系统不得不开辟新的栈进行数据保存和恢复;而尾递归就
不存在这样的问题, 因为他的状态完全由n 和 a 保存,并且,被调用函数返回的值即为要求的值,本函数再没有作用,于是本函数不再保存,直接在本函数堆栈上进行递归调用,
对于特殊情况,甚至可以不使用内存空间,直接在寄存器完成。

编译器如何判断是否尾递归?
返回的值是函数本身,没有其它选择。

看一下上述尾递归函数在gcc 4.3.2-1-1下未进行优化的编译结果:
 1         .file  "rec.c"
 2         .text
 3 .globl recurve_tail
 4         .type  recurve_tail, @function
 5 recurve_tail:
 6         pushl  %ebp
 7         movl   %esp, %ebp
 8         sub

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值