堆栈上的变量是"statically allocated"吗?

Are variables on the stack "statically allocated"?

我正在阅读 this article 并看到了这个:“这篇文章假设你已经知道并且至少基本了解内存是如何工作的 GNU/Linux 系统中的映射有效,特别是静态内存之间的区别 在堆栈中分配,在堆中动态分配内存。"

这让我很困惑,因为我认为堆栈和堆是动态分配的,意味着只在必要时分配,而全局变量和函数内部声明为 "static" 的变量是静态分配的,意味着总是分配。

例如,如果我有

void f() {
    int x = 1;
    ...
}

值 1 只会被放入堆栈,堆栈指针只会在函数 f() 被调用时递增。同样,如果我有

void f() {
    int x = malloc(1 * sizeof(int));
    ...
}

只有在调用 f() 时才会分配堆内存。但是,如果我在程序的全局部分中有 "int x = 1;" 或在函数体内有 "static int x = 1;",则任何时候我 运行 这个程序,该内存都将在数据部分中分配值 1。

我有没有错?

本身是静态分配的。随着控制流进入和离开它们的范围,堆栈中分配的变量来来去去。

堆栈以堆栈帧为单位分配。

  • 调用函数时,会为其分配一个栈帧,
  • 当函数returns时,它的栈帧消失,

并且,堆栈有助于存储函数参数和局部变量。

函数获取其堆栈帧后,是的,在堆栈帧内函数根据需要动态使用它的字节。


像堆一样动态分配堆栈

如果你想像堆一样在栈上分配内存,那么你可以使用<alloca.h>中的alloca(),它比堆快,但在大多数情况下你不需要那个,它有缺点,因此一般情况下不建议使用。


在不同的上下文中描述堆栈分配可能会更清楚:

  • 从linux thread的角度来看,(顺便说一句,每个进程默认创建时有1个线程,作为主线程),栈是固定大小的&分配在线程创建(默认情况下,IA-32 为 2Mb,IA-64 为 32Mb),您可以根据需要更改默认大小。所以你可以说这是固定的,而且是静态的。
  • 从线程或进程内部的function来看,函数启动时从线程的栈内存中为其分配栈帧,函数结束时栈帧消失。
  • 从函数内部的非静态 local variable 的角度来看,变量是根据需要从函数的堆栈帧中动态分配的。

因此,它应该被称为静态还是动态,由您决定。

静态变量只初始化一次,即使初始化语句在函数体内。

检查 wikipedia 示例:

#include <stdio.h>

void func() {
    static int x = 0; 
    /* x is initialized only once across five calls of func() and
      the variable will get incremented five 
      times after these calls. The final value of x will be 5. */
    x++;
    printf("%d\n", x); // outputs the value of x
}

int main() { //int argc, char *argv[] inside the main is optional in the particular program
    func(); // prints 1
    func(); // prints 2
    func(); // prints 3
    func(); // prints 4
    func(); // prints 5
        return 0;
}

堆栈基本上是一个静态分配的大型数组,带有一个从开头开始的可移动指针。当你调用一个函数(从 main 开始)时,指针移动(创建一个堆栈帧)并且堆栈帧中的 space 被切分并赋予局部变量(你有多少个局部变量决定了有多大你的函数的堆栈框架将是)。所以局部变量是动态的(它们只会在您进入函数后出现),但堆栈的大小是静态的。如果您在其上分配一个超大结构或使用过多的递归,您将越过末尾并且 OS 将使您崩溃——一种称为 Whosebug 的现象。 ( 图标实际上说明了这一点。底部的灰色容器代表堆栈所在的静态数组。橙色矩形是由函数调用创建的帧。就像在适当的堆栈溢出中一样,帧溢出容器并且繁荣——你的程序已经死了。帧上升的事实说明了关于堆栈的另一个相当特殊的事情——新帧的地址比旧帧低,所以 Whosebugs 确实发生在堆栈数组的开头而不是它的结尾(除非你认为数组从它们最大的索引开始并以 0 结束)。 )