从编译器的角度看C代码

1、总论

任何一个用C写的项目都是由若干文件构成,通常这些文件分为两大类:头文件和实现文件。头文件的后缀为.h,实现文件的后缀为.c。当然,也有一些文件是其他后缀,但这些文件通常也担当着头文件的角色(项目文件、配置文件及其它数据文件除外)。编译器的输入通常是实现文件,每一个实现文件对编译器来说是一个翻译单元,编译器将其翻译为目标代码,通常是一个obj文件。最后由链接器将所有的obj文件连成一个完整的可执行程序。

2、头文件

第一步,编译器首先对翻译单元进行预处理,包括对头文件和宏进行扩展。对头文件的扩展很简单,把include指令删除,然后把include指令所指定的头文件内容插入当前位置。这也就是头文件对于编译器的作用。

3、实现文件

对于编译器来说,每一个C语言程序由一系列的声明构成。所以编译器的最上端代码通常具有如下形式:

while(!Eos())
{
    Declartion();
}

上述是递归下降分析的代码片断。可以看出,编译器对C程序的编译只不过是一个不断解析声明的过程。

C语言中的声明主要分为两大类:数据声明和函数声明(定义)。数据声明的分析是编译器的基础,它定义数据的类型,并为其预留相应的存储空间。函数声明(定义)的分析是编译器的主要工作,这也是生成代码的地方。可以说,数据声明决定了程序的存储布局,函数声明则定义了程序的功能。

函数定义中的函数体分析又可看作是对声明和语句的分析,其中语句分析中的很大一块是对表达式的分析。

总的来讲,对于编译器来说,C程序的结构是一个声明的列表。其中数据声明保存了数据类型、大小、对齐等信息;函数声明则保存了返回类型、参数列表和函数体信息。程序的可执行代码主要通过函数声明中的函数体信息生成。

posted @ 2006-03-24 17:07  Goncely  阅读(234)  评论(0编辑  收藏  举报