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

接下来继续讲解程序的流程。在用高级编程语言编写的程序中对函数 [1] 进行调用,也是通过将程序计数器的值设置为存放函数的地址来实现的。但是,其原理和条件分支、循环有所不同,因为单纯用跳转指令是无法实现函数调用的。在函数调用中,当完成函数内部的处理之后,必须让程序流程返回函数被调用的地方(也就是函数调用指令的下一条指令所在的地址)继续执行。因此,如果只是跳转到函数的入口地址,处理流程就不知道在函数执行完毕后该返回到哪里了。

图 1-7 所示的 C 语言程序中,首先将 123 赋值给变量 a ,将 456 赋值给变量 b ,然后用这两个变量作为参数调用 MyFunc 函数。图中所示的地址是假设将 C 语言程序编译成机器语言后运行时的地址,由于一行 C 语言程序通常会被编译成多条机器语言指令,所以这里的地址并不是连续的。

图 1-7 函数调用的程序示例(虽然这里展示的是 C 语言代码,但实际上各地址中存放的是编译后的机器语言指令)

调用 MyFunc 函数的部分也是通过跳转指令将程序计数器的值设置为地址 0260 来实现的。函数调用指令(地址 0132)和被调用的函数(地址 0260)之间的数据传递是通过内存和寄存器来完成的。不过,当执行到函数体的出口地址 0354 时,需要将程序计数器的值设置为函数调用指令的下一条指令所在的地址 0154 才行,但这一操作无法实现。那么该怎么做才好呢?

要解决这个问题,我们需要使用调用指令和返回指令这两条机器语言指令。大家不妨把这两条指令结合起来记忆。函数调用时使用的不是跳转指令,而是调用指令。 调用指令 在将函数入口地址设置到程序计数器之前,会将函数调用的下一条指令的地址保存到名为 的内存空间中。函数体执行完毕后,会在最后(出口)执行返回指令。 返回指令 的功能是将保存在栈中的地址设置到程序计数器中。图 1-7 中,在调用 MyFunc 函数之前,程序会先将地址 0154 保存到栈中,MyFunc 函数执行完毕后,程序会从栈中读出地址 0154,然后将其设置到程序计数器中( 图 1-8 )。

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

编译高级编程语言的程序后,函数调用会转换成调用指令,函数结束的处理则会转换成返回指令。这个设计是不是很巧妙呢?

[1] 很多高级编程语言采用了与 y = f ( x ) 这种数学函数类似的语法来编写处理,它表示将 x 通过 f 处理后,将结果存放在 y 中。在函数的语法中, x 称为参数, y 中存放的值称为返回值,执行函数的功能称为函数调用。 EKFaRs/491Plnx2oV7IWViS/TQ7ubyhIUSMCXhzxR7zOL8QfG3YXcD7xaNzTibpN

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

打开