女孩和机器人一起思考

一起动脑筋 · 先看一个小故事

女孩请机器人做午餐,机器人做到一半先去煮水。煮完后,它得记得回来继续哪一步。

把过程摊开来看

沿着编号看一遍,再用自己的话讲一遍
  1. 主任务准备午餐
  2. 子任务煮水
  3. 子任务结束返回
  4. 主任务接着准备午餐

函数调用另一个函数时,调用者会等待这次调用的结果,然后继续。

把“待会儿回来做什么”写在任务卡上,就能理解为什么返回位置需要被记住。

01函数可以调用另一个函数吗?

当然可以:

int doubleValue(int x) {
    return x * 2;
}

int addDouble(int a, int b) {
    return doubleValue(a) + doubleValue(b);
}

addDouble 在执行过程中又调用了 doubleValue

02控制流去了哪里?

正在执行 addDouble进入 doubleValue返回 addDouble 继续

函数调用像一次“暂时离开”:先去完成被调用函数,再回来接着执行原来的位置。

03程序怎么知道回来以后从哪里继续?

函数调用的实现需要保存“调用完成后应该继续的位置”等信息。

在常见机器和 ABI 中,这些信息会通过调用约定、寄存器和调用栈等机制配合完成。

04每次调用里的参数一样吗?

int a = doubleValue(3);
int b = doubleValue(10);

两次调用执行同一个函数代码,但各自接收到的参数值不同,因此得到不同结果。

05同一个函数连续调用两次,会互相覆盖吗?

对于普通局部参数和局部变量,每次函数调用都具有自己的调用状态。

第一次调用

x = 3

第二次调用

x = 10

它们不是“同一个 x 同时被改成两个值”。

06函数调用会有成本吗?

通常会有一些调用、传参和返回的开销,但现代编译器有时可以进行内联优化(inlining),把函数调用消除或改写。

你已经知道了什么

  • 一个函数可以调用另一个函数。
  • 调用时控制流暂时进入被调用函数。
  • 函数完成后会回到调用点之后继续。
  • 每次调用都有自己的参数和局部状态。
  • 底层调用机制常涉及返回位置、寄存器和调用栈,但具体实现由平台决定。

下一篇:什么是调用栈?

轮到你来试一试

煮水函数返回后,午餐函数会从第一行重来吗?

想好了吗?点开看解释

不会,通常从调用之后的位置继续。返回位置让程序知道该接上哪一步。