栈变量在函数的最后一个操作中消失吗?

huangapple go评论69阅读模式
英文:

stack variable disappears at the last action of a function?

问题

尾递归的优势在于我们在代码的最后一个操作中再次调用函数(递归),因此不需要保存堆栈变量。

只要这样做,这个行为会是一样的吗?我不能确定字符串会保留在堆栈中而不会被清除?

void foo(char* c){
    c[0]='b';     
    printf("%s",c);
}
void foo2(){
    char str[]="aaa";
    foo(str);
}
int main(){
    foo2();
}

还是我可以确保在foo2中的字符串会一直存在,直到函数结束(达到最终作用域)。我在询问的是str,它是foo2函数的局部变量,是否仍然可用,还是这个局部变量(str)会在调用foo(str)后被清除,因为在这个函数foo2中没有更多的操作要执行。

我想了解的是在foo中是否可能尝试使用一个不再可用的字符串。

输出:

baa

通过这个例子,我可以看到str直到foo2作用域的结束才消失,但我想知道这是否每次都会这样,如果是的话,这如何与尾递归的概念相符,尾递归也在最后一个操作中调用函数。

英文:

The advantage of tail recursion is that we call the function (recursion) again in the last action of the code, so the stack variables doesn't need to be saved.

So here do this will act the same? and I can't be sure that the string will stay In the stack and not will be cleaned?

void foo(char* c){
    c[0]='b';     
    printf("%s",c);

}
void foo2(){
    char str[]="aaa";
    foo(str);
}
int main(){
    foo2();
}

or I can be sure that the string in foo2 will stay until the function ends (gets to the end scope).

I am asking if str that is local variable of function foo2 will still be available, or if this local variable (str) will be cleaned because no more actions to do in this function foo2 after calling foo(str).

I want to understand if could be that in foo I will try to use a string that is not available anymore.

Output:

baa

By just this example I can see that str didn't disappear until got to the end of foo2 scope, but I want to know if this will be like this every time, and if yes how this makes sense with the idea of tail recursion that also calls a function in the last action.

答案1

得分: 1

是的,因为您在函数foo2返回之前使用它。在调用foo之后,foo2将等待foo返回。

您的示例不是递归。递归是指函数调用自身。尾递归的示例:

void foo(char *x, size_t n)
{
    if(x[n])
    {
        x[n] = 'b';
        printf("%s\n", x);
        foo(x, n + 1);
    }
}

int main(void)
{
    char s[4] = "aaa";
    foo(s, 0);
}

https://godbolt.org/z/66PTrrY83

尾递归是指函数在函数中的最后一个操作是调用自身。这种情况下,编译器可以更容易地优化掉递归(这是一种昂贵的操作)。在上面的示例中,启用优化后,编译器将完全消除递归。

英文:

> or I can be sure that the string in foo2 will stay until the function
> ends (get to the end scope).

Yes as you use it before the function foo2 returns. After the call to foo foo2 will wait until foo returns.

Your example is not a recursion of any kind. Recursion is when the function calls itself. Exmaple of tail recursion:

void foo(char *x, size_t n)
{
    if(x[n])
    {
        x[n] = 'b';
        printf("%s\n", x);
        foo(x, n + 1);
    }
}

int main(void)
{
    char s[4] = "aaa";
    foo(s, 0);
}

https://godbolt.org/z/66PTrrY83

Tail recursion if the function is calling itself as the last operation in the function. This case makes compilers work much easier as they can quite easily get rid of the recursion (which is expensive operation). In the case above when you enable optimizations the compiler will remove the recursion completely:

foo:
        cmp     BYTE PTR [rdi+rsi], 0
        je      .L6
        push    rbp
        mov     rbp, rdi
        push    rbx
        mov     rbx, rsi
        sub     rsp, 8
.L3:
        mov     BYTE PTR [rbp+0+rbx], 98
        mov     rdi, rbp
        add     rbx, 1
        call    puts
        cmp     BYTE PTR [rbp+0+rbx], 0
        jne     .L3
        add     rsp, 8
        pop     rbx
        pop     rbp
        ret
.L6:
        ret
main:
        sub     rsp, 24
        xor     esi, esi
        lea     rdi, [rsp+12]
        mov     DWORD PTR [rsp+12], 6381921
        call    foo
        xor     eax, eax
        add     rsp, 24
        ret

答案2

得分: 0

我的问题是我不太了解尾调用优化,编译器会优化尾递归,但这与局部变量在离开作用域之前仍然可用的逻辑无关。
谢谢你的帮助。

英文:

My problem was that I didn't understand enough about tail call optimizations, the compiler optimizes tail recursion and this doesn't have anything about the logic that the local variable is available until leaving the scope.
ty for your help.

huangapple
  • 本文由 发表于 2023年7月18日 16:04:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76710678.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定