我正在查看一些递归函数,来自这里:
int get_steps_to_zero(int n)
{
if (n == 0) {
// Base case: we have reached zero
return 0;
} else if (n % 2 == 0) {
// Recursive case 1: we can divide by 2
return 1 + get_steps_to_zero(n / 2);
} else {
// Recursive case 2: we can subtract by 1
return 1 + get_steps_to_zero(n - 1);
}
}
我检查了反汇编代码,以确定gcc是否进行了尾递归优化/展开。看起来它做到了,但是使用x86-64 gcc 12.2 -O3,我得到了像这样的一个函数,以两个ret
指令结尾:
get_steps_to_zero:
xor eax, eax
test edi, edi
jne .L5
jmp .L6
.L10:
mov edx, edi
shr edx, 31
add edi, edx
sar edi
test edi, edi
je .L9
.L5:
add eax, 1
test dil, 1
je .L10
sub edi, 1
test edi, edi
jne .L5
.L9:
ret
.L6:
ret
多个返回的目的是什么?这是一个错误吗?
编辑
似乎是从gcc 11.x开始出现的。在使用gcc 10.x编译时,函数的结尾如下:
.L1:
mov eax, r8d
ret
.L6:
xor r8d, r8d
mov eax, r8d
ret
比如:将结果存储在eax
中。11.x版本改为在函数开始时将eax
清零,然后在函数体内修改它,从而消除了额外的mov
指令。
return
,使用3个ret
呢? - Lundinmov eax,r8d
行处设置L1标签。但显然这是一个已知的错误。 - Lundin