在C中,大括号是作为一个堆栈框架吗?
如果我在一组新的花括号中创建一个变量,那么这个变量是从右花括号中的栈上弹出的,还是会一直拖到函数结束? 例如:
void foo() {
int c[100];
{
int d[200];
}
//code that takes a while
return;
}
将d
的过程中占用内存code that takes a while
段?
不,大括号不作为堆栈框架。 在C中,大括号只是表示一个命名范围,但是没有任何东西会被销毁,也不会在控制通过时弹出堆栈。
作为编写代码的程序员,您经常可以将其看作是堆栈框架。 在大括号中声明的标识符只能在大括号中访问,所以从程序员的角度来看,它们就像它们在声明时被压入堆栈,然后在范围退出时弹出。 但是,编译器不必生成在入口/出口处推出/弹出任何东西的代码(并且通常不会)。
还要注意,局部变量可能根本不使用任何堆栈空间:它们可以保存在CPU寄存器或其他辅助存储位置中,也可以完全优化。
因此,理论上讲, d
数组可能会消耗整个函数的内存。 但是,编译器可能会优化它,或与其使用寿命不重叠的其他本地变量共享其内存。
变量实际占用内存的时间显然是依赖于编译器的(当内部块被输入并退出函数时,许多编译器不会调整堆栈指针)。
然而,一个密切相关但可能更有意思的问题是程序是否被允许访问内部范围之外(但在包含函数内)的内部对象,即:
void foo() {
int c[100];
int *p;
{
int d[200];
p = d;
}
/* Can I access p[0] here? */
return;
}
(换句话说:编译器是否允许释放d
,即使在实践中大多数不会?)。
答案是允许编译器解除分配d
,并访问注释表明为未定义行为的p[0]
(程序不允许访问内部范围之外的内部对象)。 C标准的相关部分是6.2.4p5:
对于没有可变长度数组类型的此类对象[具有自动存储持续时间的对象], 其生存期从入口延伸到与其关联的块,直到该块的执行以任何方式结束 。 (输入一个封闭的程序段或调用一个函数会暂停但不会结束当前程序段的执行。)如果程序段递归输入,则每次创建一个新的对象实例。 对象的初始值是不确定的。 如果为对象指定了初始化,则在执行块时每次执行声明时执行初始化; 否则,每次达到声明时该值都变得不确定。
你的问题不够明确,无法明确回答。
一方面,编译器通常不会为嵌套块作用域执行任何本地内存分配 - 解除分配。 本地内存通常只在函数入口处分配一次,并在函数出口释放。
另一方面,当本地对象的生命周期结束时,该对象占用的内存稍后可以用于其他本地对象。 例如,在这个代码中
void foo()
{
{
int d[100];
}
{
double e[20];
}
}
这两个数组通常会占据相同的内存区域,这意味着函数foo
所需的本地存储总量是两个数组中最大的数组所需的数量,而不是两个数组同时存在。
后者是否有资格作为d
继续占用内存等到功能在你的问题的情况下,到底是你来决定。