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