1

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

假设我们有一个代码

  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被推入堆栈还是在每次调用函数时创建?综上所述,是否可以在编译期间将激活记录推送到堆栈上?

感谢您的回答

4

1 回答 1

0

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

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

如果您会编写return fourth;,现代编译器会发现这一点fourth==4并将程序替换为return 4.

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

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

于 2017-01-12T13:58:58.310 回答