查看原文
其他

你真的知道C语言函数调用的内幕吗?

Linux_Daily 混说Linux 2022-11-19

点击左上方蓝色“混说Linux”,选择“设为星标

第一时间看干货文章 



 1

C语言使用函数调用,我们再熟悉不过了,但是函数调用在内存中究竟发生了什么真的清楚吗?只有搞清楚内存里的内幕,才算完全搞懂函数的调用。


这里涉及一个知识点:栈。不管是函数执行还是函数调用,一定要开辟一段内存空间,这块空间就是


栈是一种“后进先出(FILO)”的逻辑结构,比如一堆碗,最先洗完的碗放在最下面,最后洗完的在最上面,吃饭的时候从最上面开始拿。最上面的碗我们称之为栈顶,最底下的碗我们称之为栈底,在内存中栈顶是低地址,栈底是高地址。这里我们可以发现,根据碗的堆叠顺序知道栈是从高地址往低地址分配内存的,与其它的内存地址从低到高分配内存有所不同。

栈内存的大小由函数定义的局部变量的具体情况而定,另外,一个程序里的所有函数的栈内存在逻辑上是连在一起的,比如a函数分配了一段栈内存,此时a函数又调用了b函数,那么b函数的栈内存会接着在a函数栈内存之后去分配,依次类推。


废话不多说,来看一张函数调用的图:

main函数运行时,系统会为main函数分配一个栈帧,用来存放main函数中定义的局部变量(还有其他数据,此处略过不计)。


总结几点比较重要的:

一、栈在函数调用中起着非常重要的作用:
  1. 向被调用函数传递参数,参数从右往左依次push到栈中;

  2. 保存函数的非静态局部变量;

  3. 返回函数的返回值

  4. 保存上下文的环境,保留之前的数据,比如:返回地址、寄存器的值等,这些值会被存到栈中。


二、每个函数的栈帧都是独立存在的,里面的局部变量也是相对独立的,当执行调用fun1函数时,系统又会马上给fun1函数分配一个栈帧,其中main里面的x、y和fun1里面的a、b,它们各自在不同的内存空间。

注意,执行fun1函数的时候,main函数并没有退出,它的栈帧也没有消失,fun1函数的栈帧是堆叠在main函数的栈帧下面的,如果fun1函数还调用了其它函数,那么栈内存就继续向下增长。


三、栈内存它是临时性的,相应函数的退出(比如fun1函数执行完return返回c 之后),栈帧就会被释放,也就是这块栈空间被释放(系统回收),然后随着逐个函数的退出,栈空间也逐个从下往上退出


四、一个程序的栈是由若干段函数的栈帧组成的,栈帧的长度取决于对应函数的局部变量的个数和类型,因此,在开发的时候,我们应尽量不要定义太大、太多的局部变量,占用内存太大的数据考虑使用堆内存。


最后,如果搞懂了函数调用背后的原理(当然其实还有很多细节),遇到问题的时候才能做到从容不迫。






往期推荐

漫画 | 细说 DSP 那些事儿

干货 | Linux 内核学习经验总结

一文搞懂 | Linux内核 CFS 调度器

动图 | 让你秒懂各种常用通信协议 

来都来了,点个在看再走吧~~~



您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存