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

假设我们有一个代码

  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); }

10-05 19:14