我知道这个标题与Is this tail-recursion?重复,但这是不同的,我无法从上一个问题中得到线索。所以我得再问一次。
代码:
int sum_n(int n, int *sum)
{
return n && (*sum += n) && sum_n(n - 1, sum);
}
据说(外语源)尾递归有两个特点:
这两个特征是判断尾递归的唯一关键因素吗?返回语句中的逻辑运算符&&
是否会影响尾递归?
最重要的是,是上面的代码尾递归?
答案 0 :(得分:6)
如上所述,它有点不确定。原因是,从技术上讲,该功能应该重新获得控制权,以便&&
结果知道要返回什么。 (但这很容易被优化掉,大多数编译器可能会这样做。)
为了确保它的尾递归,只需避免对结果做任何事情而不是返回它。
int sum_n(int n, int *sum)
{
if (!(n && (*sum += n))) return 0;
return sum_n(n - 1, sum);
}
答案 1 :(得分:3)
我认为这个函数不是尾递归。
首先,我同意,以下形式是尾递归:
int sum_n(int n, int *sum)
{
int tmp = n && (*sum += n);
if (!tmp)
return 0;
else
return sum_n(n - 1, sum);
}
但是上面的函数不与原始函数完全相同。您提供的代码应与此相同:
int sum_n(int n, int *sum)
{
int tmp = n && (*sum += n);
if (!tmp)
return 0;
else
return sum_n(n - 1, sum) ? 1 : 0;
}
区别在于,sum_n(n - 1, sum)
的返回值无法直接用作函数的返回值:它应从int
转换为_Bool
。
答案 2 :(得分:3)
不是在讨论尾递归的学术定义,但是,clang 3.3确实将sum()编译为循环,而不是递归。
.file "tail.c"
.text
.globl sum
.align 16, 0x90
.type sum,@function
sum: # @sum
.cfi_startproc
# BB#0:
testl %edi, %edi
je .LBB0_6
# BB#1: # %.lr.ph
movl (%rsi), %eax
.align 16, 0x90
.LBB0_3: # =>This Inner Loop Header: Depth=1
addl %edi, %eax
je .LBB0_4
# BB#2: # %tailrecurse
# in Loop: Header=BB0_3 Depth=1
decl %edi
jne .LBB0_3
# BB#5: # %tailrecurse._crit_edge
movl %eax, (%rsi)
.LBB0_6:
xorl %eax, %eax
ret
.LBB0_4: # %split
movl $0, (%rsi)
xorl %eax, %eax
ret
.Ltmp0:
.size sum, .Ltmp0-sum
.cfi_endproc
.section ".note.GNU-stack","",@progbits
使用命令编译:
$ clang -c tail.c -S -O2
clang版本:
$ clang -v
clang version 3.3 (tags/RELEASE_33/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix