当前位置: 首页 > news >正文

布吉商城网站建设基本流程搜索引擎竞价排名

布吉商城网站建设基本流程,搜索引擎竞价排名,最新室内设计效果图,用frontpage做网站在开发软件的过程中我们经常会遇到错误,如果你用 Google 搜过出错信息,那你多少应该都访问过Stack Overflow这个网站。作为全球最大的程序员问答网站,Stack Overflow 的名字来自于一个常见的报错,就是栈溢出(stack ove…

在开发软件的过程中我们经常会遇到错误,如果你用 Google 搜过出错信息,那你多少应该都访问过Stack Overflow这个网站。作为全球最大的程序员问答网站,Stack Overflow 的名字来自于一个常见的报错,就是栈溢出(stack overflow)。

今天,我们就从程序的函数调用开始,讲讲函数间的相互调用,在计算机指令层面是怎么实现的,以及什么情况下会发生栈溢出这个错误。

为什么我们需要程序栈?

和前面一样,我们还是从一个非常简单的 C 程序 function_example.c 看起。

// function_example.c
#include <stdio.h>
int static add(int a, int b)
{return a+b;
}int main()
{int x = 5;int y = 10;int u = add(x, y);
}

这个程序定义了一个简单的函数 add,接受两个参数 a 和 b,返回值就是 a+b。而 main 函数里则定义了两个变量 x 和 y,然后通过调用这个 add 函数,来计算 u=x+y,最后把 u 的数值打印出来。

$ gcc -g -c function_example.c
$ objdump -d -M intel -S function_example.o

我们把这个程序编译之后,objdump 出来。我们来看一看对应的汇编代码。

int static add(int a, int b)
{0:   55                      push   rbp1:   48 89 e5                mov    rbp,rsp4:   89 7d fc                mov    DWORD PTR [rbp-0x4],edi7:   89 75 f8                mov    DWORD PTR [rbp-0x8],esireturn a+b;a:   8b 55 fc                mov    edx,DWORD PTR [rbp-0x4]d:   8b 45 f8                mov    eax,DWORD PTR [rbp-0x8]10:   01 d0                   add    eax,edx
}12:   5d                      pop    rbp13:   c3                      ret    
0000000000000014 <main>:
int main()
{14:   55                      push   rbp15:   48 89 e5                mov    rbp,rsp18:   48 83 ec 10             sub    rsp,0x10int x = 5;1c:   c7 45 fc 05 00 00 00    mov    DWORD PTR [rbp-0x4],0x5int y = 10;23:   c7 45 f8 0a 00 00 00    mov    DWORD PTR [rbp-0x8],0xaint u = add(x, y);2a:   8b 55 f8                mov    edx,DWORD PTR [rbp-0x8]2d:   8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]30:   89 d6                   mov    esi,edx32:   89 c7                   mov    edi,eax34:   e8 c7 ff ff ff          call   0 <add>39:   89 45 f4                mov    DWORD PTR [rbp-0xc],eax3c:   b8 00 00 00 00          mov    eax,0x0
}41:   c9                      leave  42:   c3                      ret

可以看出来,在这段代码里,main 函数和上一节我们讲的的程序执行区别并不大,它主要是把 jump 指令换成了函数调用的 call 指令。call 指令后面跟着的,仍然是跳转后的程序地址。

这些你理解起来应该不成问题。我们下面来看一个有意思的部分。

我们来看 add 函数。可以看到,add 函数编译之后,代码先执行了一条 push 指令和一条 mov 指令;在函数执行结束的时候,又执行了一条 pop 和一条 ret 指令。这四条指令的执行,其实就是在进行我们接下来要讲压栈(Push)和出栈(Pop)操作。

你有没有发现,函数调用和上一节我们讲的 if…else 和 for/while 循环有点像。它们两个都是在原来顺序执行的指令过程里,执行了一个内存地址的跳转指令,让指令从原来顺序执行的过程里跳开,从新的跳转后的位置开始执行。

但是,这两个跳转有个区别,if…else 和 for/while 的跳转,是跳转走了就不再回来了,就在跳转后的新地址开始顺序地执行指令,就好像徐志摩在《再别康桥》里面写的:“我挥一挥衣袖,不带走一片云彩”,继续进行新的生活了。而函数调用的跳转,在对应函数的指令执行完了之后,还要再回到函数调用的地方,继续执行 call 之后的指令,就好像贺知章在《回乡偶书》里面写的那样:“少小离家老大回,乡音未改鬓毛衰”,不管走多远,最终还是要回来。

那我们有没有一个可以不跳转回到原来开始的地方,来实现函数的调用呢?直觉上似乎有这么一个解决办法。你可以把调用的函数指令,直接插入在调用函数的地方,替换掉对应的 call 指令,然后在编译器编译代码的时候,直接就把函数调用变成对应的指令替换掉。

不过,仔细琢磨一下,你会发现这个方法有些问题。如果函数 A 调用了函数 B,然后函数 B 再调用函数 A,我们就得面临在 A 里面插入 B 的指令,然后在 B 里面插入 A 的指令,这样就会产生无穷无尽地替换。就好像两面镜子面对面放在一块儿,任何一面镜子里面都会看到无穷多面镜子。

Infinite Mirror Effect,如果函数 A 调用 B,B 再调用 A,那么代码会无限展开,图片来源

看来,把被调用函数的指令直接插入在调用处的方法行不通。那我们就换一个思路,能不能把后面要跳回来执行的指令地址给记录下来呢?就像前面讲 PC 寄存器一样,我们可以专门设立一个“程序调用寄存器”,来存储接下来要跳转回来执行的指令地址。等到函数调用结束,从这个寄存器里取出地址,再跳转到这个记录的地址,继续执行就好了。

//未完待续....

http://www.15wanjia.com/news/23623.html

相关文章:

  • 企业做网站带来的好处企业官网建站
  • 网站建设公司深圳百度免费咨询
  • 都匀网站制作产品网络推广深圳
  • 济南手机网站设计武汉网站推广
  • seopeix西安seo优化公司
  • 玉林做网站公司河南网站seo
  • 创维爱内购网站现在外贸推广做哪个平台
  • 群晖 wordpress 根目录seo职业技能培训班
  • 建设申请网站爱站网关键词查询工具
  • 网店代运营收费多少钱北京网优化seo优化公司
  • 无锡做网站公司哪家好电话app拉新
  • 建网站挣钱 优帮云宣传网站有哪些
  • 本地安装wordpress步骤seo外包推广
  • 站长工具综合查询ip东莞网站推广方案
  • 做网站 博客百度关键词seo排名
  • 手机网站 微信支付游戏推广员每天做什么
  • web前端需要哪些技术seo综合查询是什么
  • wordpress多域一网青岛网站seo服务
  • 昆明做一个公司网站多少费用seo包年优化费用
  • wordpress 主题 菜单搜索引擎优化指的是什么
  • 有什么做树状图的网站新产品上市推广策划方案
  • 松江区做网站的公司推广网站制作
  • 网站和虚拟服务器网址查询地址查询
  • 英文网站后台维护百度风云榜游戏排行榜
  • 如何组做网站产品网络营销策划
  • 辽宁网站建设平台app推广拉新平台
  • 一个网站主机多少钱一年seo搜索排名优化公司
  • 在哪些网站做收录比较快搜狗搜图
  • 搜狗网站提交网络销售真恶心
  • 北京到安阳的火车票seo是指什么岗位