我很难理解激活记录(我已经阅读了多个答案)。
假设我们有一个代码
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推入堆栈还是每次调用函数时都会创建?说完其他所有内容,是否有可能在编译期间将激活记录推送到堆栈上?
感谢您的回答
答案 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); }
。