【内功】函数栈帧的创建和销毁

简介: 函数栈帧的创建和销毁

目录

一、电脑存储

二、简单例题讲解

醍醐灌顶-原来是这样!

<1>.局部变量是怎么创建的?

<2>.为什么局部变量的值不初始化是随机的?

<3>.函数是怎么传参的?传参的顺序是怎么样的?

<4>.形参和实参是什么关系?

<5>.函数调用结束后是怎么返回的?返回值是怎么带回来的?

三、遇见安然遇见你,不负代码不负卿!


【前言】

这部分内容老师上课时不会说的哦,之所以写这篇是因为想让大家对于函数栈帧的创建和销毁这块内容有着更加深刻的理解和认识。

一、电脑存储

电脑上的存储有:硬盘、内存、寄存器

这里谈一下寄存器的概念:

寄存器是集中到CPU上的,寄存器是一块存储空间

寄存器分为:

  • eax
  • ebx
  • ecx
  • edx
  • ebp
  • esp

【敲黑板】:

要理解函数栈帧,就必须要理解ebp、esp这两个寄存器中存放的是地址,而且这两个地址是用来维护函数栈帧的。


二、简单例题讲解

//研究函数栈帧的创建和销毁
#include<stdio.h>
int Add(int x, int y)
{
  int z = 0;
  z = x + y;
  return z;
}
int main()
{
  int a = 10;
  int b = 20;
  int c = 0;
  c = Add(a, b);
  printf("%d\n", c);
  return 0;
}

【敲黑板】:

main()函数也是被其他函数调用的


醍醐灌顶-原来是这样!

<1>.局部变量是怎么创建的?

先为函数分配栈帧空间,对栈帧空间的值进行初始化,然后在栈帧里面给局部变量分配一点空间

<2>.为什么局部变量的值不初始化是随机的?

局部变量在创建之前,它们在的空间就已经有随机值了,所以局部变量不初始化值是随机值

<3>.函数是怎么传参的?传参的顺序是怎么样的?

当我们去调用函数的时候,其实在调用函数之前,我们就已经把参数从右向左开始压栈,当我们真正进入形参函数的时候,通过指针的偏移量找到了形参

<4>.形参和实参是什么关系?

形参确实是我们在压栈的时候开辟的空间,它和我们的实参只是在值上是相同的,空间却是独立的,所以形参是实参的一份临时拷贝,改变形参不会影响实参

<5>.函数调用结束后是怎么返回的?返回值是怎么带回来的?

在调用函数之前就已经将call指令的下一条地址压栈了,把调用这个函数的上一个函数的ebp存进去(压栈)了,当我们函数调用完,要返回的时候,弹出ebp,就能找到上一层函数的栈底指针往下走就能找到上一层函数的栈帧,由于我们记住了call指令的下一条指令的地址,当我们函数调用结束返回时就直接跳到call指令的下一条指令的地址处了,让我们函数调用完可以返回


三、遇见安然遇见你,不负代码不负卿!

后面会将动图补充进来的哦,那样就好理解许多啦。


相关文章
|
7月前
|
存储 安全 C语言
深度剖析c语言程序 -- 函数栈帧的创建和销毁(纯肝货)-2
深度剖析c语言程序 -- 函数栈帧的创建和销毁(纯肝货)-2
|
7月前
|
存储 编译器 C语言
深度剖析c语言程序 -- 函数栈帧的创建和销毁(纯肝货)-1
深度剖析c语言程序 -- 函数栈帧的创建和销毁(纯肝货)-1
|
7月前
|
编译器 容器
关于函数栈帧的创建和销毁
关于函数栈帧的创建和销毁
|
程序员 编译器 C语言
细谈函数栈帧的创建与销毁
我们在写C语言代码时,经常会把一个独立的功能抽象为函数,所以C程序是以函数为基本单位的。那函数如何调用?函数的返回值如何返回的?函数参数是如何传递的?这些问题都与函数栈帧有关系。
186 0
|
7月前
|
存储 编译器
初识函数栈帧的创建与销毁(笔记)
初识函数栈帧的创建与销毁(笔记)
|
编译器 C语言 容器
函数栈帧的创建和销毁(一)
函数栈帧的创建和销毁
120 1
|
编译器
剖析函数栈帧的创建与销毁,斯高一版本!!
剖析函数栈帧的创建与销毁,斯高一版本!!
84 0
函数栈帧的创建和销毁(二)
函数栈帧的创建和销毁
69 0
|
编译器 C语言
函数的栈帧与销毁(栈帧可不是战争哦)
函数的栈帧与销毁(栈帧可不是战争哦)
55 0
|
存储 编译器 程序员
C语言代码函数栈帧的创建与销毁(修炼内功)
目录 在前期的学习中我们可能有很多困惑 例如:局部变量是怎么创建的 为什么局部变量的值是随机值 函数是怎么样传参的 传参的顺序是什么 形参和实参的关系是什么 函数调用是怎么做的 函数掉调用结束后怎么返回的 这篇博客我们来修炼自己的内功,掌握好这篇博客的大部分知识就已经很不错了 我们用到VS2013这个编译器,目的是为了看到更详细的函数封装内容 提示不要使用太过高级的编译器,因为越高级的编译器越不容易观察。同时这里需要注意的是在不同的编译器下,函数调用过程中栈帧的创建是略有差异的,不是完全相同的,具体细节取决于编译器