3.5 程序的工作原理
程序既可以指开发完成的可执行文件及其相关文件和数据,也可以指正处于开发阶段的源代码及其相关文件和数据(IDE称之为程序工程)。程序工程包含一个或多个编译单元、资源文件、静态库及配置文件等。把一个C++/C程序工程转变为一个可执行程序要经历编译预处理、编译、连接等过程。一个可执行文件的结构不一定就是它被加载到内存中运行时的内存映像,但是至少包含代码段、静态数据段、堆栈段这三个部分。其中代码段包含源程序中的可执行语句序列,静态数据段存放全局变量、静态对象、符号表等,堆栈段留给函数和线程使用。堆(heap)和自由存储空间不属于程序,而是属于操作系统,但是应用程序可以通过动态内存分配指令来获得它们的使用权。
现在的计算机仍然遵循冯·诺依曼的“存储程序控制”原理。本质上,任何一个程序都是由待处理的数据和一系列处理它们的指令(操作)组成的,这些指令通过内存地址来访问待处理的数据。程序中任何复杂的操作(例如,显示复杂的图形或窗口)最终都被转换为简单的加法运算让计算机来执行。程序在运行的时候首先要求把内存操作数的地址通过数据总线(DB)传递到CPU寄存器中,然后CPU指示将它送到地址总线(AB)上,接着内存单元的数据就会“流”入CPU的接收寄存器中,然后取第二个操作数,最后执行加法运算。函数调用则是首先提取函数体的首地址到CPU寄存器中,然后将CPU指令指针修改为这个寄存器中的值,CPU从内存提取下一条指令时就可以取到函数的第一条指令,这样就实现了函数跳转。
典型的C++/C运行环境如图3-2所示。
图3-2 C++/C程序运行环境
存在于二进制可执行程序中的只是指令、地址和数据,没有别的东西(实际上地址也是一种特殊的数据),这就是“运行时”的本质。像标识符(类型名、变量名、函数名等)、类型定义、const关键字、访问限定符public/private/protected、引用(&)等只是存在于源代码中,它们不会被带入二进制可执行程序,这是“编译时”的本质。C++/C源代码中的语句、指针和变量都将被转换成二进制程序中的指令、地址和数据。因此,通过名字直接引用一个变量、对象及其成员,这样的代码在编译和连接完成后,实际上都被转换成了通过变量、对象或成员变量的地址(即内存单元的地址)进行访问。