C/C++: 函数调用, 栈的大小是如何被确定的

本文探讨了函数调用过程中的栈管理机制,包括局部变量的分配与回收、栈帧的构建与销毁等内容,并解析了编译器如何预先确定栈空间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

每个函数调用都要压栈, 
栈用来存放局部变量和形参以及状态指针,
可是很多时候变量是按程序逻辑动态创建的, 编译器不可能知道函数块需要多少局部变量啊?

比如这样一个函数: 
void test()
{
  if(someCondition) {double a = 123.0;} else {int b = 456;} // 栈的大小应按sizeof(a) 还是 sizeof(b)计算? 

}

_test    PROC
; Line 2
    push ebp
    mov    ebp, esp
    sub    esp, 12                    ; 0000000cH

................

 ; Line 13
    mov    esp, ebp
    pop    ebp
    ret    0
_test    ENDP

编译器需要知道局部变量所需的总空间,即所有局部变量所需空间的和。楼主的例子里就是8+4=12


void test()
{
     int a = 1;
     int b = 2;
}

push ebp //*保存caller的frame基址, push操作会使栈顶寄存器ESP地址前移4Bytes
mov ebp,esp //*原栈顶变为新frame的基址,因而栈是连续的
add esp,-0x08 //*栈顶前移8 Bytes, 预留变量a,b的空间,这证明frame的大小的确是编译时确定的.
mov [ebp-0x04],0x00000001 //*局部变量a赋值1
mov [ebp-0x08],0x00000002 //*局部变量b赋值2
pop ecx //这个不明白了, ecx计数寄存器, 在这pop它干啥????
pop ecx // ????而且还pop两次?????
pop ebp //*恢复caller的frame基址
ret //*返回

这里两次pop,就相当于add esp,8

编译器认为前者的速度和指令大小更划算

你观察一下,pop ecx 这条指令只需一个字节,而加减esp则需要三个字节

这种事情编译器常干

ecx在这里只是凑个位置,因为pop指令总需要个操作数

另外,#52楼的问题,其实ebp继续往前翻,不就可以“窥看”到返回地址/实参

#53楼,只需要把转换即可
int p;
_asm mov p,ebp
void* r=(void*)p;



函数调用的确是是个压栈的过程; 函数返回后,压栈的数据被弹出。
栈的大小,应该由编译器和os共同决定吧。
编译器中,有frame 和 record的概念。来控制函数调用和返回。以及发生异常时,栈的回退(unwinded)等。

函数调用中其相关信息和其局部变量的空间都在栈上分配,而且是编译器自动分配。

至于你说的是sizeof(a) 还是sizeof(b);个人觉得应该大于sizeof(a) + sizeof(b);

因为函数调用的过程,是一个上下文切换的过程,其间,首先要保存现场、然后将函数的返回地址及局部变量压栈、执行函数、返回、恢复现场。 如果写过汇编程序,这个就很容易理解了。
这些都是有编译器实现的,具体细节我们不必关心。

alloc 可以在栈上分配内存。你可以通过在函数内部定义一个足够大数组,来看看,你的编译器分配的stack size。


现代系统,都是一个线程一个栈,所以叫做线程栈,windows默认一个线程1MB的栈,每新开一个线程,就配套分配1MB的栈,当然也可以指定大小




注意区分两种存在方式:一个是在文件里,一个是在虚拟内存里

静态和全局变量保存在.exe/.dll文件的数据区,运行时则被加载到虚拟内存的某个区域,既不在堆,也不在栈

局部变量实质上是以代码的形式,即相关的push/pop指令,保存在.exe/.dll文件的代码区,运行时,代码被加载到虚拟内存的某个区。而执行代码里的push/pop时,局部变量被压入/弹出栈




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值