C - 如何查找堆栈中的最大变量数



在执行以下程序期间,堆栈中一次绑定的最大变量数是多少:

int x, y, z;
int g(int a, int b) {
  int c = 5 * a + b;
  return c;
}
int f(int a, int b) {
  a = g(a, 5);
  return g(b, a);
}
int main() {
  int a, b, c;
  x = y = z = 0;
  a = 5; b = 6;
  c = f(a, b);
  printf("%d", c);
}

如果有人知道如何找到它,请。你能解释一下该怎么做才能在可能给出的每个代码中找到它吗? 没有任何优化。

再比如:

int x,y;
int f(int a){
  if (a!=5)
    return f(--a);
  else 
    return a;
}
int main(){
  int a,b;
  a=8;b=6;
  x=f(a);
  y=f(b);
  printf("%d", x+y);
  return 0;
}

这是答案6以上吗?因为第一次返回,返回变量 3 次。第二次返回返回一次数字,我们在 main 中有两个变量,所以 6?

您可以在头脑中(或在调试器中(逐步运行程序,并且可以计算调用堆栈的每一帧中的所有活动变量(然后获得它们的最大总和(。

在您的特定示例中,假设没有优化,最深的调用堆栈发生在g语句return c;main调用f调用。所以我们有 3 个调用堆栈帧,其中 3 个变量用于 g (abc ;我假设形式就像局部变量,这在实践中并不总是正确的!(,2 个变量用于f(ab(,3 个变量用于main

您的老师可能希望您将调用堆栈绘制到最深的状态。我把这个留给你。

在实践中,几个变量不占用任何堆栈空间,例如,因为它们位于寄存器中,或者与另一个变量共享一个堆栈槽。这是编译器和 ABI 以及特定于处理器架构和操作系统的。

然而,正如Ilya所回答的那样,一个好的编译器会为了优化目的而转换你的程序,所以在实践中答案可能会有所不同。

如果使用GCC,您可以尝试查看生成的汇编代码(使用gcc -fverbose-asm -S(,您将看到结果和所用变量的数量取决于优化标志(即 -O1-O2等...或缺乏它们(。您也可以使用 GCC 特定的 -fstack-usage 标志。您甚至可以尝试使用 -fdump-tree-all 标志来gcc它提供了数百个转储文件,详细解释了编译器中程序的各种中间表示(Gimple、SSA 等(。

另请阅读有关延续(也可能是call/cc(,tail call,recursion和内联扩展的wiki页面。

顺便说一句,调用堆栈的存在并不是 C99 标准要求的严格意义上的(但我知道没有不使用任何调用堆栈的 C 实现(。如果你很好奇,你应该阅读 A.Appel 的旧纸质垃圾收集可以比堆栈分配更快(这解释了不使用任何调用堆栈的 SML 实现,因为它在垃圾收集堆中分配每个"调用帧",又名"延续帧"(。

我还建议编译您的示例(使用 gcc -Wall -g(,然后在gdb调试器中逐步运行它们。经常使用gdbdisplaystepbacktraceframe命令。

这取决于编译器和优化设置。好的优化算法将生成如下内容:

int main() {
  printf("%d", 155);
}
其他

算法将生成其他内容。因此,尝试使用反汇编器来获取编译结果。