【发布时间】:2013-10-12 20:01:32
【问题描述】:
很长一段时间以来我一直被教导的方式是,当我运行一个程序时,首先进入堆栈的是 main 方法的堆栈帧。如果我从 main 中调用一个名为 foo() 的函数,那么一个堆栈帧就是局部变量(自动对象)的大小,并且参数也会被推送到堆栈上。
但是,我遇到了一些与此相矛盾的事情。我希望有人能澄清我的困惑或解释为什么真的没有任何矛盾。
第一个矛盾:
在 Bjarne Stroustrup 的《C++ 编程语言》第 3 版一书中,它在第 244 页上说,“每次在程序执行中遇到其声明时,都会创建一个命名的自动对象。”如果这还不够清楚,在下一页它说,“每次控制线程通过局部变量的声明时,都会执行局部变量的构造函数。”
这是否意味着堆栈帧的总内存不是一次全部分配,而是在遇到变量声明时逐块分配? 另外,这是否意味着如果由于 if 语句而没有遇到变量声明,则每次堆栈帧的大小可能都不相同?
第二个矛盾:
我已经在汇编中做了一些编码(具体来说是 ARM),我的课程被教授的方式是,当调用一个函数时,我们立即使用寄存器并且从不压入当前的任何局部变量除非该算法无法使用有限数量的寄存器执行,否则将函数放到堆栈中。即便如此,我们也只推送了剩余的变量。
这是否意味着在调用函数时,可能根本不会创建堆栈帧? 这是否也意味着堆栈帧的大小可能会因使用寄存器而有所不同?
【问题讨论】:
-
你可能想看看Arm link and frame pointer,主要是我们希望编译器尽可能快,所以没有关于它们必须如何生成汇编代码的一般规则,尤其是优化。如果编译器可以推断事物,例如在叶函数中,它将利用这一事实。如果对象不是 POD 并且它不知道构造函数的实现,则编译器必须为对象创建空间;如果它想减少堆栈使用、选择缓存等,它可以立即分配或不分配。
标签: c++ assembly arm callstack cpu-registers