我很难理解激活记录(我已经阅读了有关它的多个答案)。
假设我们有一个代码
int n( int a){
int b = a/2;
return a + b;
}
int main (){
int first = 1;
int second = n(first);
int third = 3;
int fourth = n(third);
return 0;
}
当程序开始执行时,堆栈将被填充,例如
| first |
__________
| activation_record |
| first |
____________________
| third |
| activation_record |
| first |
_____________________
| activation_record1 |
| third |
| activation_record |
| first |
_______________________
激活记录将把静态局部变量,函数地址,函数参数和返回值放在其堆栈上,我应该理解它,例如在完成激活记录(或被调用者函数)执行后,将激活记录替换为其返回值和它的堆栈被释放?
同样,同一函数被多次调用,并且具有应该保存返回数据位置的调用堆栈,是将相同的activation_record推入堆栈还是在每次调用函数时创建它?不管怎么说,在编译期间是否可以将激活记录推送到堆栈上?
感谢您的回答
最佳答案
您会得到不同的答案,因为可能有不同的解决方案。 C ++标准仅描述可观察的行为,而堆栈布局则不可观察。
特别是,现代编译器会将您的程序缩减为int main() { return 0; }
,因为只有返回值是可见的。
如果您要编写return fourth;
,则现代编译器会找出fourth==4
并将其替换为return 4
。
但是,让我们暂时假设这些优化不会发生,并且您有一个常规的x64编译器。同样,结果将有所不同:通用的x64 ABI在CPU寄存器中而不是堆栈中传递函数参数并返回值。这并不使用所有x64寄存器,因此局部变量也可以放入寄存器中。
不同的激活记录也将重叠,因为它们不会同时使用。实际上,这不是优化,而是必要的,因为编译器通常无法确定将进行多少次调用。例如:for (char&c : string) { c = toupper(c); }
。