理解程序的运行

我们用数据的眼光看世界,便已经进入了计算机的思维方式中。更多的问题紧接着产生了:代表着真实概念的数据,究竟是以怎样的方式、存在于计算机中何处呢?对数据做操作时,这些数据实际上又发生了怎样的变化呢?

为了回答这些问题,我们需要暂时中止我们思维的自由流动,聚焦在一个更为实在和具体的话题上:理解一个程序是怎样运行的。

函数调用

我们已经知道函数可以用来封装一套对数据的操作逻辑。而在整个程序的实际运行过程中,函数也是程序运行的基本单元。从函数出发,程序的运行可以简单归纳为下面两个要点:

  1. 每个程序存在一个入口函数,作为程序逻辑的开始;
  2. 函数之间通过相互调用组合成更为复杂的逻辑。

直观来讲,当一个程序开始运行时,其入口函数(一般称为 main 函数)首先被调用而开始执行。main 函数执行过程中,能够调用其他函数,继续执行其他函数的逻辑。这些函数又能再度调用更多的函数,如此类推。而每个函数调用结束后,程序会返回其调用者、继续执行其调用函数的逻辑,直至结束。

以这样的调用/返回机制作为程序运行的根基,比较符合思维的直觉,好处也是显然的。其一,函数调用时进入、返回时退出,整个过程对于调用者而言是独立的、可控的:调用的函数终究会返回调用者、仅仅留下一个结果,调用者可以继续执行自己的逻辑。如此,不同函数能够更加独立自主地实现逻辑,而不用担心调用其他函数会改变和干扰自身的执行。其二,这种调用/返回机制,实际上为函数提供了一种形似数学函数的编程接口:函数可接收输入(函数参数)、产生输出(函数返回值)。这样的接口将函数调用和函数本身的实现分离开来,从而让每个函数都成为可自由组合的运行单元。

回顾上一节所讲,函数是对数据操作的一个封装。结合函数调用的机制,我们可以更具体地讲明:函数接收参数作为输入数据,对数据作一系列操作,而后返回结果数据作为返回值。回到对数据本身的关注上,我们还要进一步理解,在整个函数的运行过程中所涉及的这些数据,是如何组织和存储的呢?

函数调用栈