激活记录

时间:2017-01-12 13:00:23

标签: c++ memory stack activation-record

我很难理解激活记录(我已经阅读了多个答案)。

假设我们有一个代码

  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推入堆栈还是每次调用函数时都会创建?说完其他所有内容,是否有可能在编译期间将激活记录推送到堆栈上?

感谢您的回答

1 个答案:

答案 0 :(得分:0)

您会得到不同的答案,因为可能有不同的解决方案。 C ++标准只描述了可观察的行为,并且堆栈布局是不可观察的。

特别是,现代编译器会将程序减少到int main() { return 0; },因为只有返回值是可观察的。

如果您已经写了return fourth;,现代编译器就会想出fourth==4并用return 4替换该程序。

但我们暂时假设这些优化没有发生,而且你有一个常规的x64编译器。同样,结果会有所不同:常见的x64 ABI传递函数参数并返回CPU寄存器中的值,而不是堆栈中的值。这不使用所有x64寄存器,因此局部变量也可以进入寄存器。

不同的激活记录也会重叠,因为它们不会同时使用。这实际上不是优化,而是必要的,因为编译器通常无法确定将进行多少次调用。示例:for (char&c : string) { c = toupper(c); }