【问题标题】:c/c++ allocate on stackc/c++ 在栈上分配
【发布时间】:2013-11-01 11:06:45
【问题描述】:

我正在阅读有关堆栈指针的 [1] 以及了解 ebp(函数堆栈的开始)和 esp(结束)的需要。文章说你需要知道这两个,因为堆栈可以增长,但我不明白这在 c/c++ 中是如何实现的。 (我不是在谈论另一个函数调用,因为在我看来这会使堆栈增长,做一些事情,然后递归地被弹出并返回到调用前的状态)

我做了一些研究,只看到有人说new 在堆上分配。但是指针将是一个局部变量,对吗?这在编译时是已知的,并在调用函数时保留在堆栈中。

我开始认为,也许循环的局部变量数量不受控制

int a;
for (int i = 0; i < n; ++i)
  int b = i + 3;

但是不,这不会分配 n 次 b,并且只保留 1 个 int,就像为 a 一样。

那么……有什么例子吗?

[1):http://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames

【问题讨论】:

  • C 和 C++ 中的所有变量都存在于 作用域 上下文中。例如,函数中的局部非静态变量仅对该函数是自动的。也就是说,您认为代码中b 的存在范围是什么?
  • 从编译器的角度来看,您的示例中没有任何“不受控制”的地方。
  • 文章在哪里说“你需要知道这两个,因为堆栈可以增长”?它只讨论在堆栈上传递的参数。
  • 通常给定帧的堆栈大小是固定的,但是我见过(在古代)一个我不记得名字的函数,它可以通过简单地扩展堆栈来分配内存堆栈帧的大小。这比 malloc 调用快得多,而且它不必被释放(事实上,这是不可能的)——而是在当前堆栈帧终止时自动释放。
  • @mah 你想到的是alloca(有时带有一些下划线前缀),它至今仍然存在。

标签: c++ c cpu-registers


【解决方案1】:

您可以使用 stdlib 中的 alloca 函数在堆栈上分配内存。我不建议在生产代码中使用此功能。很容易破坏堆栈或堆栈溢出。

【讨论】:

  • C99 添加了对同样以这种方式分配的可变长度数组的支持。 int foo(unsigned sz) { char bar[sz]; ...
【解决方案2】:

使用 EBP 更多的是为了方便。可以只使用 ESP。问题在于,当函数的参数被压入堆栈时,所有变量和参数的相对于 ESP 的地址都会发生变化。

通过将 EBP 设置为堆栈上固定的已知位置,通常在函数参数和局部变量之间,所有这些元素的地址在函数的整个生命周期内相对于 EBP 保持不变。它还可以帮助调试,因为函数末尾的 ESP 值应该等于 EBP 的值。

我知道在编译时以不确定的方式增长堆栈的唯一方法是重复使用 alloca。

【讨论】:

    【解决方案3】:

    确实在堆栈上分配了一个指针。在 32 位和 64 位架构上,大小通常分别为 4 或 8 个字节。因此,您在编译时静态地知道指针的大小,如果您选择这样做,您可以将它们保留在堆栈中。

    这个指针可以指向空闲存储,你可以动态地为它分配内存——而不必事先知道大小。此外,将堆栈帧保持为空通常是一个好主意,编译器甚至会通过(可调整的)限制“强制”这一点。如果我没记错的话,MSVC 有 1MB。

    所以不,您无法创建在编译时未知大小的堆栈帧。您发布的代码的堆栈框架将有 3 个整数(a、b、i)的空间。 (可能还有一些不相关的填充、阴影空间等。)(在运行时扩展堆栈帧的大小在技术上是可行的,但您几乎永远都不想这样做。)

    【讨论】:

      猜你喜欢
      • 2013-09-26
      • 2017-01-25
      • 2015-11-23
      • 1970-01-01
      • 2018-06-29
      • 2011-06-11
      • 2011-12-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多