C和指针 2.1 环境

缘起

《C与指针》 2.1节

分析

ANSI C标准的任何一种实现中,都要有2种环境——编译和运行. 前者将C源码转换为可执行的机器指令,后者用于实际执行代码. ANSI C没有规定两个环境必须要位于同一台机器上. 例如交叉编译器就是在一台机器上编译,但是产生的代码却可以运行于不同类型的机器上(甚至没有os的硬件平台上,如微波炉控制器).

编译

编译过程首先由预处理器对源码进行操作——以实际值替代#define指令定义的符号以及读入由#include指令包含的文件的内容. 然后经过预处理的源码要经过解析(这一步是产生绝大多数错误和警告信息的地方),随后便产生了目标代码(UNIX的.o文件或者MS-DOS中的 .obj文件,视平台不同而不同). 目标代码是机器指令的初步形式,如果编译命令行中包含优化选项的话,则优化器还会对目标代码进行进一步的处理——让目标代码的效率更高(但优化会耗费时间). 尔后各个目标代码由链接器(Linker) 绑在一起,形成单个完整的可执行程序(.exe或者 .out).链接器同时也会引入C标准库(其实确切讲是C标准库的实现,亦即lib目录)中任何被该程序用到的函数,而且链接器还可以搜索程序员自定义的lib库,将其中需要的库函数也链接到程序中.

执行

首先,程序必须要载入到内存中去. 而载入的任务,在存在os的环境(下面简称A)中,由os完成. 在不存在os的环境中(下面简称B,例如微波炉控制器),程序的载入必须由手工安排或者把可执行代码永久存储到ROM(只读内存)中完成. 不是存储在堆栈(stack)中的尚未初始化的变量将在这个时候得到初始值.

然后程序开始执行,在A中,通常一个小型的启动程序和程序链接在一起. 该小型启动程序负责一系列的日常事务——例如收集命令行参数以便使得程序能够访它们. 接着调用main函数.

现在开始执行程序代码,绝大多数A中,程序将使用一个运行时堆栈(stack)——它用于存储函数的局部变量和返回地址。程序亦可以使用静态(static)内存存储区,存储于静态内存的变量在程序的整个执行过程都将一直保留它们的值.

程序执行的最终阶段就是程序终止.