购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

接下来,我们继续介绍程序的流程。哪怕是高级语言编写的程序,函数 [1] 调用处理也是通过把程序计数器的值设定成函数的存储地址来实现的。不过,这和条件分支、循环的机制有所不同,因为单纯的跳转指令无法实现函数的调用。函数的调用需要在完成函数内部的处理后,处理流程再返回到函数调用点(函数调用指令的下一个地址)。因此,如果只是跳转到函数的入口地址,处理流程就不知道应该返回至哪里了。

图 1-7 是给变量 a b 分别代入 123 和 456 后,将其赋值给参数(parameter)来调用 MyFunc 函数的 C 语言程序。图中的地址是将 C 语言编译成机器语言后运行时的地址。由于 1 行 C 语言程序在编译后通常会变成多行的机器语言,所以图中的地址是离散的。

{%}

图1-7 程序调用函数示例(这里直接展示了 C 语言的源代码,实际上各地址存储的应该是变换成机器语言后的程序)

此外,通过跳转指令把程序计数器的值设定成 0260 也可实现调用 MyFunc 函数。函数的调用原点(0132 地址)和被调用函数(0260 地址)之间的数据传递,可以通过内存或寄存器来实现。不过,当函数处理进行到最后的 0354 地址时,我们知道应该将程序计数器的值设定成函数调用后要执行的 0154 地址,但实际上这一操作根本无法实现。那么,怎么办才好呢?

机器语言的 call 指令和 return 指令能够解决这个问题。建议大家把二者结合起来来记忆。函数调用使用的是 call 指令,而不是跳转指令。在将函数的入口地址设定到程序计数器之前, call 指令 会把调用函数后要执行的指令地址存储在名为栈 的主存内。函数处理完毕后,再通过函数的出口来执行 return 命令。 return 命令 的功能是把保存在栈中的地址设定到程序计数器中。如图 1-7 所示,MyFunc 函数被调用之前,0154 地址保存在栈中。MyFunc 函数的处理完毕后,栈中的 0154 地址就会被读取出来,然后再被设定到程序计数器中(图 1-8)。

{%}

图1-8 函数调用中程序计数器和栈的职能

在编译高级编程语言的程序后,函数调用的处理会转换成 call 指令,函数结束的处理则会转换成 return 指令。这样一来,程序的运行也就变得非常流畅。

注释

[1] 很多高级编程语言都采用类似于 y = f ( x ) 这样的数学函数的语法来记述编写处理。我们知道,该数学函数的意思是将 x 这个值通过 f 处理后得到数值 y 。如果套用函数的语法, x 就是参数, y 就是返回值,执行函数的功能就是函数调用。 pQhIxa7pvG8WGsCG/qorIyrjGIZZZxtt5Z/LjmDImhL0ySdohEtKQt8eHh8ZYWFj

点击中间区域
呼出菜单
上一章
目录
下一章
×

打开