C语言 堆栈结构如何与函数内的复合语句一起工作?



我正在尝试学习C编程,但无法理解堆栈的工作原理。

我读到的任何地方都发现,当一个函数被称为堆栈帧时,会在堆栈中创建,其中包含函数调用参数、返回地址和局部变量的所有数据。并且当函数返回时,堆栈帧被移除,释放内存。

但是,如果我们在函数中有一个具有自己的变量的复合语句呢?是对于块的局部变量的内存也是在函数调用时在堆栈帧内分配的,并在返回时释放。

int main(){
int a = 10;
if(int a<50){
int b=9;
}
else{
int c=10;
}
}

当函数开始执行时,bc的内存是否分配了a? 并在函数返回时解除分配?

如果是这样,那么除了在函数的开头或函数的另一个块内声明变量时变量的可见性之外,没有其他区别。

请解释一下。

C 标准没有指定如何实现这些东西。C 标准甚至没有提到堆栈!堆栈是实现函数调用的常用方法,但标准中没有任何内容需要堆栈。所有这些事情都是特定于实现的细节。对于发布的代码,标准仅指定变量何时在范围内。

所以你的问题没有一般的答案。答案取决于您的特定系统,即处理器、编译器等。

如果您的系统使用堆栈(很可能(,编译器可以为所有 3 个变量保留堆栈空间,也可以为 2 个变量保留空间,即一个用于a,而bc共享另一个。这两种实现都是合法的。编译器甚至被允许将变量直接放置在某些寄存器中,这样就不需要在堆栈上保留任何内容。

您可以通过查看生成的汇编代码来检查您的特定系统。

C 实现可以通过多种方式实现这一点。假设您的示例对象abc实际上以某种方式在您的代码中使用,导致编译器实际上为它们分配内存而不是优化它们。然后:

  • 编译器可以在函数启动时为所有abc分配堆栈空间(通过减少堆栈顶部指针(,并在函数结束时释放它。
  • 编译器可以在函数启动时为a分配堆栈空间,然后在需要bc空间时在函数中间分配空间(再次通过减少堆栈指针(,然后在每个块结束时释放该堆栈空间。
  • 在一个好的现代编译器中,编译器可能会分析对象的所有活动生存期,并找到以重叠方式使用堆栈空间的某种最佳解决方案。我所说的"活动生存期"是指从设置对象值到最后一次需要该值的时间(不是 C 标准对"生存期"的定义(。例如,在int a = f(x); … g(a); h(y); a = f(y); … g(a);中,a实际上有两个生命周期,从最初的赋值到第一个g(a),从赋值a = f(y);到第二个g(a);。如果编译器需要内存来存储a,它可能会在这两个生命周期内使用不同的内存。

由于上述原因,C对象用于什么内存可能会变得相当复杂。特定的内存位置可能一次用于a,另一时间用于b。它可能取决于代码中的循环和goto语句。它还取决于是否获取对象的地址 — 如果获取地址,编译器可能必须将对象保留在一个位置,以便地址一致。(它可能能够在不这样做的情况下逃脱,这取决于它如何看到地址被使用。

基本上,编译器可以自由使用堆栈、其他内存,并以它选择的任何方式寄存器,只要程序的可观察行为保持 C 标准定义的状态。

(可观察的行为是程序的输入/输出交互、写入文件的数据以及对易失性对象的访问。

所述示例无效,因为 if-else 语句中没有括号。但是,在下面的示例中,所有变量通常在输入函数时分配:

int main(void)
{
int a = 10;
if (a < 50) {
int b = 9;
} else {
int c = 10;
}
}

正如用户"500 - 内部服务器错误"所提到的,这是一个实现问题。

最新更新