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

    文章

    2998

    浏览量

    73881
  • C语言
    +关注

    关注

    180

    文章

    7598

    浏览量

    136162
收藏 人收藏

    评论

    相关推荐

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

    C语言使用函数调用,我们再熟悉不过了,但是函数调用在内存
    发表于 09-07 11:47 807次阅读

    C语言内存知识总结:memset函数和calloc函数

    memset(翻译:清零)是计算机C/C++语言初始化函数。作用是将某一块内存
    发表于 10-24 10:40 1094次阅读

    C函数调用机制与栈帧原理详解

    当一个C函数调用时,函数的参数如何传递、堆栈指针如何变化、栈帧是如何被建立以及如何被消除的,一直缺乏系统性的理解,因此决定花时间学习下
    发表于 06-08 10:49 1214次阅读
    <b class='flag-5'>C</b><b class='flag-5'>函数</b><b class='flag-5'>调用</b>机制与栈帧原理详解

    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 4640次阅读

    C语言回调函数学习

    对指针的应用是C语言编程的精髓所在,而回调函数就是C语言里面对函数指针的高级应用。简而言之,回调
    发表于 05-27 09:44 7195次阅读

    系统调用函数库分析及实例

    作为用户我们极少接触系统调用,但是我们熟悉C 语言,对库函数调用并不陌生。C
    发表于 06-23 16:46 46次下载
    系统<b class='flag-5'>调用</b><b class='flag-5'>函数</b>库分析及实例

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

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

    C语言代码调用汇编函数需要注意什么

    来看下混合语言工程,就比如在汇编程序调用C函数,或者在C
    的头像 发表于 11-12 11:04 2792次阅读

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

    C语言使用函数调用,我们再熟悉不过了,但是函数调用在内存
    的头像 发表于 01-13 14:09 1103次阅读

    RPC如何在远程过程中调用

    RPC(Remote Procedure Call Protocol)即远程过程调用,也就是调用函数是在其它的控制板上运行的,不需要理会底层的通讯协议。
    的头像 发表于 02-07 09:52 869次阅读
    RPC如何在远程<b class='flag-5'>过程中</b><b class='flag-5'>调用</b>?

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

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

    什么是函数调用

    函数调用,就是使用我们已经定义好的函数,或者C语言自带的库函数
    的头像 发表于 04-04 17:21 5655次阅读