【问题标题】:What happens to stack Frames when main() calls main()当 main() 调用 main() 时堆栈帧会发生什么
【发布时间】:2012-10-23 07:37:33
【问题描述】:

请考虑以下代码:

#include <stdio.h>

int main()
{
    static int counter=5;

    printf ("Counter = %d\n", counter);

    if (counter--)
    {
        main();
    }

    return 0;
}

编译:

gcc test.c -ansi -Wall –pedantic

执行:

[root@mars home]# ./a.out 
Counter = 5
Counter = 4
Counter = 3
Counter = 2
Counter = 1
Counter = 0

这里 main() 调用它自己()。

似乎main()函数的原始stackframe每次被自己调用main()都会被覆盖。

但是返回地址是什么?函数可以返回到自己的堆栈帧吗?

请帮我澄清这个疑问。

谢谢。

【问题讨论】:

  • int counter 被声明为static,因此分配在函数的堆栈上,而是分配在全局堆上。
  • 除此之外,堆栈不会被覆盖。每次调用函数时都会压入一个新堆栈,并在返回时再次弹出
  • @alk 我不小心投了赞成票。静态变量既不在堆栈也不在堆中分配。它们通常位于数据段中,具有用于初始化和未初始化(BSS)的不同部分。但是,这可能因实现而异。

标签: c main stack-frame


【解决方案1】:

它不会被覆盖。这是一个普通的函数调用(在这种情况下是递归的)。您可能对 counter 变量感到困惑。这个变量被声明为static,这意味着它只被初始化一次,所以下面的行只被“执行”了一次:

static int counter=5;

换句话说,您可以将counter 视为仅初始化一次的全局变量(值为5)。在每次调用main 时,它都会递减,直到达到零。在那之后,所有main 函数都返回,所以堆栈是unwinded(就像在正常的函数调用中一样)。

【讨论】:

    【解决方案2】:

    这在许多计算机语言中是很正常的,称为“递归”。每次调用函数都会创建一个新的堆栈帧,因此不会被覆盖。

    外层main()的返回地址和往常一样是运行时库。内层main()的返回地址就是外层main()。

    在您的示例中弄混了水的一件事是您将 counter 声明为静态的。这意味着它是在数据段中的堆上而不是在堆栈上分配的(正如注释中的 alk 所解释的那样),因此每次调用 main() 都共享相同的 counter 实例。

    【讨论】:

    • 不一定在堆上。它很可能只是一个全局变量。
    • 谢谢,是的,我感觉堆不太对劲,但在我写这篇文章时有一个心理障碍。
    • 事实上,永远不要在堆上,因为堆需要被显式清除。它是数据段的一部分,通常具有用于初始化和未初始化值 (BSS) 的单独部分
    【解决方案3】:

    简短回答:这是一个简单的递归案例。所以它会分配新的栈帧而不覆盖之前的帧。

    长答案:
    ma​​in() 调用 ma​​in() 时堆栈帧会发生什么:
    C 不区分 main 和任何其他函数。这是一个简单的、正常的递归情况。 'main' 之所以特殊,只是因为编译器附带的默认 crt0.asm(或编译器中的任何名称)在其基本初始化(如堆栈指针等)完成后调用 main。
    除了这个区别之外,没有什么特别之处了。

    【讨论】:

      猜你喜欢
      • 2019-01-01
      • 2010-11-22
      • 1970-01-01
      • 2017-06-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多