堆栈上的变量是"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 结束)。
)
我正在阅读 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 的现象。
(