调用函数时,栈帧真的会被压入栈中吗? [英] Does a stack frame really get pushed onto the stack when a function is called?

查看:18
本文介绍了调用函数时,栈帧真的会被压入栈中吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很长一段时间以来我一直被教导的方式是,当我运行程序时,立即进入堆栈的第一件事是 main 方法的堆栈帧.如果我从 main 中调用一个名为 foo() 的函数,那么一个栈帧是局部变量(自动对象)和参数的大小,也会被压入栈中.

The way I've been taught for quite some time is that when I run a program, the first thing that immediately goes on the stack is a stack frame for the main method. And if I call on a function called foo() from within main, then a stack frame that is the size of the local variables ( automatic objects) and the parameters gets pushed onto the stack as well.

但是,我遇到了一些与此矛盾的事情.我希望有人能解决我的困惑或解释为什么真的没有任何矛盾.

However, I've ran into a couple things that contradict this. And I'm hoping someone can clear up my confusion or explain why there really aren't any contradictions.

第一个矛盾:

在 Bjarne Stroustrup 所著的《C++ 编程语言》第 3 版一书中,它在第 244 页说,每次在程序执行中遇到它的声明时,都会创建一个命名的自动对象."如果这还不够清楚,在下一页它会说,每次控制线程通过局部变量的声明时,都会执行局部变量的构造函数."

In the book, "The C++ Programming Language" 3rd edition by Bjarne Stroustrup, it says on page 244, "A named automatic object is created each time its declaration is encountered in the execution of the program." If that's not clear enough, on the next page it says, "The constructor for a local variable is executed each time the thread of control passes through the declaration of the local variable."

这是否意味着堆栈帧的总内存不是一次性分配的,而是在遇到变量声明时逐块分配?此外,这是否意味着如果由于 if 语句而未遇到变量声明,则堆栈帧可能不会每次都具有相同的大小?

Does this mean that the total memory for a stack frame is not allocated all at once, but rather block by block as the variable declarations are encountered ? Also, does this mean that a stack frame may not be the same size every time if a variable declaration was not encountered due to an if statement ?

第二个矛盾:

我已经在汇编中做了一些编码(具体来说是 ARM),我的课程被教授的方式是当一个函数被调用时,我们立即使用寄存器并且从不推送当前的任何局部变量除非该算法无法在有限数量的寄存器下执行,否则将函数加载到堆栈中.即便如此,我们也只推送了剩余的变量.

I've done a little coding in assembly ( ARM to be specific ), and the way my class was taught was that when a function was called, we immediately used the registers and never pushed any of the local variables of the current function onto the stack unless the algorithm was not possible to perform with the limited amount of registers. And even then, we only pushed the leftover variables.

这是否意味着在调用函数时,可能根本不会创建堆栈帧?这是否也意味着堆栈帧的大小可能因寄存器的使用而不同?

Does this mean when a function is called, a stack frame may not be created at all ? Does this also imply that a stack frame may differ in size due to the use of registers ?

推荐答案

关于你的第一个问题:

对象的创建与数据本身的分配无关.更具体地说:对象在堆栈上有其保留空间这一事实并不意味着其构造函数何时被调用.

The creation of the object has nothing to do with the allocation of the data itself. To be more specific: the fact that the object has its reserved space on the stack doesn't imply anything about when its constructor is called.

这是否意味着堆栈帧的总内存不是一次性分配的,而是在遇到变量声明时逐块分配?

Does this mean that the total memory for a stack frame is not allocated all at once, but rather block by block as the variable declarations are encountered?

这个问题确实是特定于编译器的.堆栈指针只是一个指针,二进制文件如何使用它取决于编译器.实际上有的编译器可能会保留整个激活记录,有的可能只是一点点的保留,有的可能会根据具体的调用动态保留等等.这甚至与优化紧密结合,以便编译器能够按照它认为更好的方式安排事情.

This question is really compiler specific. A stack pointer is just a pointer, how it is used by the binary is up to the compiler. Actually some compilers may reserve the whole activation record, some may reserve just little by little, some other may reserve it dynamically according to the specific invocation and so on. This is even tightly coupled with optimization so that the compiler is able to arrange things in the way it thinks is better.

这是否意味着在调用函数时,可能根本不会创建堆栈帧?这是否也意味着堆栈帧的大小可能因寄存器的使用而不同?

Does this mean when a function is called, a stack frame may not be created at all ? Does this also imply that a stack frame may differ in size due to the use of registers ?

同样,这里没有严格的答案.通常编译器依赖寄存器分配算法,这些算法能够以最小化溢出"的方式分配寄存器(在堆栈上)变量.当然,如果您正在手工编写汇编,您可以决定将特定寄存器分配给整个程序中的特定变量,因为您通过它们的内容知道您希望如何使其工作.

Again, there is no strict answer here. Usually compilers rely on register allocation algorithms that are able to allocate registers in a way that minimizes "spilled" (on stack) variables. Of course, if you are writing in assembly by hand, you can decide to assign specific registers to specific variables throughout your program just because you know by their content how you want to make it work.

编译器无法猜测这一点,但它可以看到变量何时开始使用或不再需要,并以最小化内存访问(即堆栈大小)的方式安排事物.例如,它可以实现一个策略,使得一些寄存器应该由被调用者保存,另一些由被调用者保存并分配或其他什么.

A compiler can't guess this, but it can see when a variable starts to be used or is no longer needed and arrange things in a way that minimize memory accesses (so stack size). For example, it could implement a policy such that some registers should be saved by the called, some others by the callee and assign or whatever.

这篇关于调用函数时,栈帧真的会被压入栈中吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆