写这篇总结的缘由仅仅出于巧合,五一前帮一位同学看51的程序,在查看汇编代码的时候(事实上我当时的汇编知识基本都还给了老师),无意中问起我“某个局部变量的声明怎么没有对应的汇编语句”,我没有答出来。当时也只是把它当做一种常识给记了下来,平时不论还是在DSP、16位的单片上还是PC平台上编写c程序,由于程序不是很复杂且芯片资源通常足够,因此很少会考虑内存分配、堆栈方面的内容。这几天在看《Linux c 一站式编程》这本书关于变量内容的时候突然想起这个问题,顿时觉得很有必要把深究一下。

因为网络账号还没充钱的缘故,ubuntu系统还不能及时升级,因此在VC平台下做了以下相关试验。代码如下:

int main(void)

{

int d;

int f = d+1;

d = 1;

d = hello(5,10);

return 0;

}

对应的汇编代码如下:

16:   int main(void)

17:   {

00410960   push        ebp

00410961   mov         ebp,esp

00410963   sub         esp,48h

00410966   push        ebx

00410967   push        esi

00410968   push        edi

00410969   lea         edi,[ebp-48h]

0041096C   mov         ecx,12h

00410971   mov         eax,0CCCCCCCCh

00410976   rep stos    dword ptr [edi]

18:

19:

20:       int d;

21:       int f = d+1;

00410978   mov         eax,dword ptr [ebp-4]

0041097B   add         eax,1

0041097E   mov         dword ptr [ebp-8],eax

22:       d = 1;

00410981   mov         dword ptr [ebp-4],1

23:        //printf('Hello world!\n');

24:        //printf("a = %f,b=%f,c=%f",a,b,c);

25:        //getch();

26:       d = hello(5,10);

00410988   push        0Ah

0041098A   push        5

0041098C   call        @ILT+5(_hello) (0040100a)

00410991   add         esp,8

00410994   mov         dword ptr [ebp-4],eax

27:       return 0;

00410997   xor         eax,eax

28:   }

从以上汇编代码20、21两行中可以看到“int d”语句确实没有对应的函数声明。但是在用d给f赋值的时候,d却对应了dword ptr [ebp-4],这一点刚开始的时候很是疑惑,后来在看过几篇相关文章后得知,局部变量的声明和释放是由编译器调整栈指针(Stack Pointer)位置来完成的[1],编译器首先根据变量的类型和数量计算存储局部变量所需的空间,然后调整ESP的值来为局部变量分配空间。“int d;” 在编译的时候应该是将变量d 与地址 dword prt[ebp-4]对应了起来,既d的内存地址为ebp-4到ebp-7;同理,f值往上调整,对应ebp-8到ebp-11。

然而,了解了以上内容还远不够理解函数压栈出栈的原理,于是对main函数下面对应的17行做了分析,考虑linux平台下的情况[],主要针对ESP和EBP两个栈寄存器作分析解释。以下是通过单步调试的方式得到的结果:

图1  未单步前

未运行单步执行前,程序和寄存器值如图1所示。ESP = 0012FF84 ,EBP = 0012FFC0;这是旧的(在函数调用时就是主调函数的)栈对应的空间。

图2  执行  “00410960   push        ebp”

执行的“push ebp”后,程序和寄存器值如图2所示。ESP = 0012FF80,EBP = 0012FFC0;因为是要在原来栈的基础上开辟新的栈空间,因此,在旧栈(不知道该如何称呼,暂且这么认为)的栈顶上移了四个字节作为新栈的栈底。因此ESP由原来的0012FF84变为0012FF80 。

图3  执行  “00410961   mov         ebp,esp”

“mov  ebp,esp”是为了将新的栈底指针赋值为ebp,如图3所示。ESP = 0012FF80,EBP = 0012FF80 。

图4  执行  “00410963   sub         esp,48h”

“ sub   esp,48h”则是为了给局部变量在栈中分配一定的存储空间,如图4所示。ESP由原来的0012FF80减小到0012FF38,这里需要注意的是0012FF80到0012FF7C为旧栈中的栈顶对应的四个字节,因此局部变量的分布实际是从地址0012FF7C到地址0012FF34共72个字节空间。

图5  执行  “push        ebx ;push        esi;push        edi”

接下来,连续执行三个push,将相应的寄存器值压栈。

时间限制,下面转写了参考中的文献以备忘。

1.在一个栈中,依据函数调用关系,发起调用的函数(caller)的栈帧在下面(高地址方向),被调用的函数的栈帧在上面。

2.每发生一次函数调用,便产生一个新的栈帧,当一个函数返回时,这个函数所对应的栈帧被清除(eliminated)

”[1]

c语言局部变量压栈顺序,C 程序局部变量压栈出栈的理解相关推荐

  1. 元素入栈顺序确定,共有多少种出栈顺序?----Python

    文章目录 问题描述 对栈的理解 题目的思考 python代码 卡特兰数 扩展思路 问题描述 前几天看到一个题目,假设五个元素的入栈顺序为e1.e2.e3.e4.e5,那么共有多少种出栈顺序?一时之间思 ...

  2. 出栈(释放栈)和引用栈内数据意义不等同,和嵌套有关系但不是等同关系,局部变量进栈操作,不是局部变量自动带有进栈指令。汇编语言后局部变量操作是包含进栈操作指令PUSH和栈内地址存储数据调用,出栈。

    出栈(释放栈)和引用栈内数据意义不等同,和嵌套有关系但不是等同关系,局部变量进栈操作,不是局部变量自动带有进栈指令.汇编语言后局部变量操作是包含进栈操作指令PUSH和栈内地址存储数据调用,出栈. 2. ...

  3. PAT甲级1051 Pop Sequence:[C++题解]模拟栈、判断序列是否是合法的出栈序列

    文章目录 题目分析 题目来源 题目分析 来源:acwing 分析: 题意:将1~N压栈,判断给定序列是否是合法的出栈序列. 对于序列1~N中的每个值i,先将其压入栈.然后对于它就有两种处理方法:要么压 ...

  4. 理解——先序遍历是入栈过程,中序遍历是出栈过程

    遇到这样一道题:先序序列为a,b,c,d的不同二叉树的个数是多少? 拿到这个问题 首先,要了解到先序遍历和中序遍历都是需要用到栈,其中,先序遍历是入栈过程,中序遍历是出栈过程 然后,二叉树的先序序列和 ...

  5. 全栈路线_程序员该走全栈路线还是深度专家路线?

    程序员该走全栈路线,还是深度路线?相信这个问题是所有程序员都会思考的一个问题. 先说说何谓全栈?全栈工程师,英文Full Stack engineer,一般是指能独立完成产品开发的人,同时具备前端和后 ...

  6. 问题-栈S最多能容纳4个元素,现有6个元素按A、B、C、D、E、F顺序进栈,问可能的出栈顺序。...

    住栈的特性:对于取出栈内元素每次只能从栈顶开始取(后进先出(栈满时,只能先出后进)) 由于栈内只能容纳4个元素: 所以 E F不可能第一个出栈: 当栈内少于四个元素时 既可以选择进栈,也可以选择出栈 ...

  7. PTA 栈 (20分)(全网首发)(实现一个栈Stack,要求实现Push(出栈)、Pop(入栈)、Min(返回最小值的操作)的时间复杂度为O(1))

    题目描述: 我们知道平凡的栈有几个操作: push(value) 将 value 压入栈 pop() 将栈顶元素弹出, 并返回这个弹出的元素. 现在我们想要在平凡栈的基础上实现以下几个操作: push ...

  8. 栈顶指针不同进行“进、出”栈的易错题

    1.若一个栈元素用数组data[1..n]存储,初始栈顶指针top为n,则以下元素x进栈最适合的操作是______. A.top++; data[top]=x; B.data[top]=x; top+ ...

  9. 判断出栈顺序是否正确

    先说一下题目: 假设有一个栈S,每次我们可以把序列A(含N个元素)中的第一个元素移入栈S,也可以是从栈顶弹出一个元素放入出栈序列B.这 样,经过N次入栈和出栈操作后,我们可以得到一个出栈序列B. 现在 ...

最新文章

  1. Hotpatch潜在的安全风险
  2. 数学题 贪心+二分答案
  3. 模板库 | 销售管理类报表,邀您提反馈
  4. 传统到敏捷的转型中,谁更适合做Scrum Master?
  5. linux系统找运行指令,Linux系统常用指令总结
  6. 技术面试别扯智力题!
  7. Maven的配置和使用(三)
  8. Photoshop数位板无压感解决方法
  9. AgileEAS.NET SOA 中间件/敏捷软件开发平台
  10. 打开本地flash webview open swf
  11. 微缩脚步趋缓 摩尔定律由于EUV微影技术延迟失去动力
  12. Axure 8 网页滚动效果+APP上下垂直拖动效果
  13. 登录界面---油管大佬
  14. 本周大新闻|CES 2023 AR/VR最全汇总
  15. 局域网(LAN)端口与广域网(WAN/外网)端口映射——实现让局域网机器在外网做服务器...
  16. IIS 服务器常见漏洞
  17. php点击切换图片的底部导航,如何优雅地使用BottomNavigationView实现底部导航栏+fragment切换效果...
  18. Linux Shell相关记笔记
  19. 时域同步平均TSA-学习笔记
  20. 痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU启动那些事(3)- Serial Downloader模式(sdphost/MfgTool)...

热门文章

  1. Linux-epoll机制
  2. 护照读取_如何使用Android读取护照
  3. javascript通过console.log()控制台输出各种字体样式(3D文字、彩色背景色体)
  4. JS 实现红包雨效果,倒计时开红包 兼容移动端
  5. SDCC 2016架构运维峰会(成都站),讲师议题抢先看!
  6. 有这么一种茶几,它带着触摸屏!
  7. 语义鸿沟、异构鸿沟、数据缺失,多模态技术如何跨过这些坎?
  8. LabVIEW通过NI OPC实现与三菱FX 5U系列PLC的通讯
  9. 张蕾:2019年的机会在哪里?我看好这5个领域!
  10. 计算机信息技术导论课程总结,信息技术导论结课报告.docx