0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言函数调用过程中的内存变化解析

电子设计 来源:TOMORROW 星辰 作者:TOMORROW 星辰 2020-12-11 16:21 次阅读

相信很多编程新手村的同学们都会有一个疑问:C 语言如何调用函数的呢?局部变量的作用域为什么仅限于函数内?这个调用不是指C 语言上的函数调用的语法,而是在内存的视角下,函数的调用过程。本文将从C 语言调用实例,内存视角,反汇编代码来探讨C 语言函数的调用过程,也可以说是C 语言函数调用过程图解。通过这个C 语言函数调用过程图解,同学们将会知道,C 语言函数在调用时,内存空间是怎样变化的。

要想理解这一个过程还好涉及到函数栈帧的概念。函数栈帧指的是,在调用函数时,系统在栈空间中给函数所分配的一段连续空间。其中 ebp(栈帧基址指针)则是指明了当前函数的栈帧基地址,对函数的资源(局部变量、实参等)的访问,都要通过 ebp+offset(偏移量)来进行访问。而 esp 则是栈指针,指示当前栈空间栈顶的位置。

以下代码即是此次探讨 C 语言函数调用过程的实例源码:

intsubFunc(intabc)
{
intdef=0x9999;
abc=0x8888;
returnabc;
}

int_tmain()
{

subFunc(0x2222);

return0;
}

源码很简单,在一个主函数中,调用一个带参数的子函数。源码使用 Visual Studio2010 进行调试,并同时查看内存窗口、反汇编窗口及变量窗口。

进入调试模式,并将断点定在调用子函数 subFunc()处,然后运行并观察。

通过观察窗口,可以知道,此时还是在执行 main 函数,而 ebp(栈帧基址指针)指向的是 0x0073fb64,esp=0x0073fa98。从反汇编代码可以看到,在调用函数前,需要先将参数压栈,也就是将实参存到了 0x0073fa94 处,然后再调用到子函数。

进入到子函数时,esp 已经变成了 0x0073fa8c,而 0x0073fa90 处存放的是,子函数执行完后返回到 main 函数中的地址。进入到子函数后,先将 main 函数的 ebp 压栈,然后将当前栈顶指针的值赋值给 ebp 作为当前子函数的 subFunc()的栈帧基址指针。此时 esp 和 ebp 都变成了 0x0073fa8c。

紧接着,可以看到,esp 一下子被减去了 0x0cch,也就是说栈空间一下子增长了 0x0cch,并且这段空间全部被赋值为 0xcc。再往下看,可以看到子函数中的局部变量被分配在了 0x0073fa84 处(因为变量是 32 位的,然后 CPU 却是 64 位的,所以空了 32 位不作使用),也就是说,这一段被初始化为 0xcc 的栈空间是被用来给局部变量分配空间的。

接下来再看,在 main 函数传递了一个实参 0x2222 给子函数 subFunc 中的形参 abc。在对 abc 进行读写时,其实就是在对前面实参所被存储的空间进行读写,也就是说形参在作为参数也作为局部变量的同时,它所被分配的内存空间是在函数栈帧基址 ebp 之下。

而子函数被执行完后,返回的过程则是一个与上面过程相逆的过程。将相应的数据出栈,恢复 ebp 等信息,释放子函数的栈空间,返回到主函数。所以局部变量的作用域只是在函数中,当函数被执行完返回时,函数的栈帧都被释放了,局部变量等数据也就没有了,不存在了,也就是说局部变量的生命周期是与函数的生命周期等同的。

经过以上的 C 语言函数调用过程图解,相信已经理解了 C 语言在内存中是如何调用的了。然后可以总结并得出下面的函数调用的栈帧图解。从函数调用的层面看,栈空间是被从下往上一块一块地增长的,并且是后分配的先被释放,先分配的后被释放。

编辑:hfy

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 内存
    +关注

    关注

    8

    文章

    2767

    浏览量

    72752
  • C语言
    +关注

    关注

    180

    文章

    7528

    浏览量

    128409
收藏 人收藏

    评论

    相关推荐

    C语言使用函数调用的知识点

    C语言使用函数调用,我们再熟悉不过了,但是函数调用在内存中究竟发生了什么真的清楚吗?只有搞清楚内存
    发表于 09-07 11:47 669次阅读

    在LabVIEW调用C语言——调用函数节点

    在LabVIEW调用C语言——调用函数节点学习LabVIEW也有一段时间了,从
    发表于 04-20 09:14

    请问如何调用matlab脚本节点,在调用过程中程序会有何反应

    请问如何调用matlab脚本节点,在调用过程中程序会如何反应?
    发表于 02-22 20:19

    实际项目开发过程中常用C语言函数的用法

    讲解在实际项目开发过程中常用C语言函数的用法。  1 printf 函数  函数原型:int p
    发表于 12-10 13:38

    请问时钟中断函数void SysTick_Handler(void)在调用过程中不会改变r4-r11吗?

    为什么没有将r4-r11进行入栈保护操作,难道时钟中断函数void SysTick_Handler(void)在调用过程中不会改变r4-r11吗?我看到在pendsv异常中断中有r4-r11进行入栈保护操作
    发表于 08-19 00:11

    请问一下函数调用过程是怎样的?

    函数调用过程是怎样的?在父函数调用函数时,通常会执行的步骤在子函数
    发表于 04-20 06:10

    【原创】C语言中的动态内存-----栈内存

    作者:蔡琰老师(张飞实战电子高级工程师)C语言程序的动态内存分为栈内存区域和堆内存区域两种。栈内存
    发表于 07-07 14:18

    C语言函数如何调用

    C语言函数如何调用
    发表于 10-18 09:06

    ARM函数调用过程说明

    ARM函数调用默认4个参数用R0-R4传递,大于4个用堆栈传递,局部变量保存在堆栈,下面以一个简单的函数来说明这个过程。先定义
    发表于 04-26 10:05

    ARMv8的函数调用栈是什么意思?调用栈的内存管理是怎样的

    调用解析概念: 任意体系结构的CPU,都设计了一套通用寄存器、状态寄存器及其他控制寄存器,用以维系系统的正常运行。函数调用过程中,CPU一般都需要处理几件事情:保存母
    发表于 05-13 10:36

    C++教程之函数的递归调用

    C++教程之函数的递归调用 在执行函数 f 的过程中,又要调用 f 函数本身,称为
    发表于 05-15 18:00 35次下载

    C语言入门教程-malloc函数和free函数

    malloc函数和free函数 假设您的程序在执行过程中需要分配一定量的内存。您可以随时调用malloc
    发表于 07-29 11:58 4554次阅读

    使用过程仿真函数模拟PID控制的过程

    中断并设定循环时间为200ms。例如OB31 2) 在OB31中调用PID函数PID_compact,然后在全局库中打开库文件《Sim_controllprocess_V13_SP1》,并调用过程仿真
    的头像 发表于 05-27 17:31 3503次阅读

    C语言使用函数调用在内存中究竟发生了什么?

    C语言使用函数调用,我们再熟悉不过了,但是函数调用在内存中究竟发生了什么真的清楚吗?只有搞清楚内存
    的头像 发表于 01-13 14:09 745次阅读

    C语言函数调用的形式及过程

    C语言函数调用时的数据传递 在调用有参函数时,主调函数和被调
    的头像 发表于 03-10 14:28 1113次阅读