一、内存结构
内存大致可以分为四个部分:代码段,静态存储区,堆,栈。
具体划分如下图所示:

栈:在执行函数时,函数内部局部变量的存储单元都可以在栈上创建,函数执行结束后会自动释放内存。栈内存的分配运算内置于处理器的指令中。效率高,但分配的内存容量有限,程序发生错误时,很有可能出现栈溢出。
堆:又称为动态内存分配区,程序在执行的时候用malloc或new申请指定大小的内存,程序员自己负责在任何时候用free或delete释放内存。若在申请后未释放,在程序结束时有可能会有OS自动回收,或者造成内存泄露,因此,使用时一定要注意。
静态存储区:包括程序中明确被初始化的全局变量、静态变量、常量以及未被初始化的数据。内存在程序编译时已经分配好,这块内存在整个运行期间一直存在。
代码区:存放程序代码,代码区是可以共享的(其他的执行程序可以调用它),整个内存中只有一份。

栈和堆的区别
1.管理方式不同
栈由编译器自动管理,堆由程序员控制。
2.空间大小不同
栈是向低地址扩展的结构,是连续的内存区域,因此栈顶和栈底是规定好的,容量有限,若用户使用过多的栈空间,会产生溢出。堆是向高地址扩展,不是连续的内存区域,堆获得的空间较大,分配时也比较灵活。
3.是否产生碎片
对于堆来说,频繁的malloc/free,new/delete会是空间不连续,造成大量碎片,使得程序效率降低。而栈不存在这样的问题。
4.增长方向不同
堆和栈相对生长
5.分配方式
堆由程序员通过使用malloc、free、new、delete来进行管理。栈由编译器申请释放,栈的动态内存分配通过alloca函数完成。
6.分配效率不同
栈是机器系统提供的数据结构,计算机在底层对栈提供支持。堆是C库函数提供的,堆的效率比栈低得多。

二、函数的调用过程(栈帧)
每一次的函数调用都是一个过程,我们将这个过程称为函数的调用过程。在这个过程中,会开辟栈空间用来保存本次函数调用过程中临时变量以及现场保护等工作,这块栈空间我们称之为函数栈帧。栈帧的维护需要两个寄存器也叫帧指针,即ebp和esp,esp中存放栈顶地址,ebp存放栈底地址。esp和ebp一次只能存放一个地址。
以下是函数调用的详细过程:

假设函数a调用了函数b,函数b调用了函数c,函数b有三个参数,从左至右依次为参数1,参数2,参数3。
1.函数a在调用函数b的时候,首先将函数b的参数以相反的顺序依次压入栈中,即,从最后一个参数开始压栈。
2.函数a使用call指令调用函数b,并将call指令下的一条指令的地址当做返回地址压入栈中。(汇编call命令的两个功能:1.保存当前指令的下一个指令的地址。2.pc指针跳转到调用函数的入口地址。)
3.在函数b的栈帧中,首先保存函数a的栈底地址,再将函数a的栈顶地址当做函数b的栈底地址,即图中所示的push ebp和mov ebp,esp这两条指令。
4.然后,从ebp的位置开始存放函数b的局部变量,将这些变量的地址依次存放在栈中,先定义的先入栈,后定义的后入栈。
注意:在不同的编译器上函数的调用过程可能会有所不同,但大致思想相同。

汇编的堆栈操作指令
1:栈是自顶向下生长
2:栈是先入后出的数据结构
3:push会使esp-4
4:pop会使esp+4
临时存放数据
传递参数
保存和恢复寄存器 PUSHF/POPF

c函数调用过程的更多相关文章

  1. 从一个新手容易混淆的例子简单分析C语言中函数调用过程

    某天,王尼玛写了段C程序: #include <stdio.h> void input() { int i; ]; ; i < ; i++) { array[i] = i; } } ...

  2. c函数调用过程原理及函数栈帧分析

    转载自地址:http://blog.csdn.net/zsy2020314/article/details/9429707       今天突然想分析一下函数在相互调用过程中栈帧的变化,还是想尽量以比 ...

  3. 函数调用过程&生成器解释

    摘自马哥解答,感谢. 函数调用过程: 假设程序是单进程,单执行流,在某一时刻,能运行的程序流只能有一个.但函数调用会打开新的执行上下文,因此,为了确保main函数可以恢复现场,在main函数调用其它函 ...

  4. Linux驱动调试-根据oops的栈信息,确定函数调用过程

    上章链接入口: http://www.cnblogs.com/lifexy/p/8006748.html 在上章里,我们分析了oops的PC值在哪个函数出错的,那如何通过栈信息来查看出错函数的整个调用 ...

  5. C语言的函数调用过程

    从汇编的角度解析函数调用过程 看看下面这个简单函数的调用过程: int Add(int x,int y) { ; sum = x + y; return sum; } int main () { ; ...

  6. 37.Linux驱动调试-根据oops的栈信息,确定函数调用过程

    上章链接入口: http://www.cnblogs.com/lifexy/p/8006748.html 在上章里,我们分析了oops的PC值在哪个函数出错的 本章便通过栈信息来分析函数调用过程 1. ...

  7. 深入理解C语言的函数调用过程 【转】

    转自:http://blog.chinaunix.net/uid-25909619-id-4240084.html 原文地址:深入理解C语言的函数调用过程 作者:wjlkoorey258     本文 ...

  8. C语言的函数调用过程(栈帧的创建与销毁)

    从汇编的角度解析函数调用过程 看看下面这个简单函数的调用过程: int Add(int x,int y) { ; sum = x + y; return sum; } int main () { ; ...

  9. C++函数调用过程深入分析<转>

    转自http://blog.csdn.net/dongtingzhizi/article/details/6680050 C++函数调用过程深入分析 作者:靠谱哥 微博:洞庭之子-Bing 0. 引言 ...

  10. 用systemtap跟踪打印动态链接库的所有c++函数调用过程

    http://gmd20.blog.163.com/blog/static/168439232015475525227/             用systemtap跟踪打印动态链接库的所有c++函数 ...

随机推荐

  1. LeetCode-630 课程表Ⅲ

    来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/course-schedule-iii 题目描述 这里有 n 门不同的在线课程,按从 1 到 n  ...

  2. 死磕rmi之 RegistryImpl

    Registry初始化 可以把注册中心理解为特殊的远程对象,这个对象就像一个容器一样,存储其他远程对象. 可以本地直接调用四大方法,也可通过调用远程对象的方式调用. 查看一下类继承关系 可参照http ...

  3. php 中解析xml文件

        public function xmltoarr($path) {//xml字符串转数组         $xml= $path;//XML文件         $objectxml = si ...

  4. 分时问候——时间类、if语句

    import java.time.LocalTime; public class Hello { public static void main(String[] args) { LocalTime ...

  5. CLIP 读书笔记

    论文:Learning Transferable Visual Models From Natural Language Supervision CLIP: Contrastive Language- ...

  6. python threading.Thread暂停、唤醒、退出 不消耗cpu

    class MyThreadSound(threading.Thread): def __init__(self): super(MyThreadSound, self).__init__() sel ...

  7. docker自动化启动停止脚本

    docker一键启动命令 sh auto.sh [start|restart|stop] [keywords...] keywords可选(包含编号,镜像名,容器名称,端口) 其中defaultLis ...

  8. QML与python互相通信

    解决python与QML的通信问题: QML中直接调用python函数 python发送信号,QML响应信号并进行相应处理 py文件 # This Python file uses the follo ...

  9. driver报错

    self.driver = webdriver.Chrome(),突然报错,运行不了 解决办法: 第一步:去检查你以安装的驱动版本,用cmd打开命令提示符:然后用命令:chromedriver 第二步 ...

  10. c语言中定义局部变量不赋初值默认

    C语言中定义局部变量不赋初值默认为随机数,全局变量定义时候不赋初值默认为0. 但是在keil3中我发现不管全局变量还是局部变量都默认是0.