在ANSI C的任何一种实现中,都存在两种不同的环境。第一种是翻译环境,在这个环境中源代码被转换成可执行的机器指令;第二种是执行环境,用于实际执行代码。
翻译
翻译阶段由几个步骤组成,组成一个程序的每一个源文件通过编译过程分别转换为目标代码。然后各个目标文件由链接器捆绑在一起,形成单一而完整的可执行程序。链接器同时也会引入标准C函数库中任何被该程序所使用到的函数。
编译过程本身也由几个阶段组成,首先是预处理器处理。在这个阶段,预处理器在源代码上执行一些文本操作。例如用实际值取代#define的值。以及读入#include包含的文件的内容。
然后源码经过解析,判断他的语句的意思。随后,产生目标代码。目标代码是机器指令的初步形式,用于实现程序的语句。
如果我们在编译程序的命令中加入要求进行优化的选项,优化器就会对目标代码进一步进行处理使他效率更高。
执行
程序的执行过程也需要经历几个阶段。
首先,程序必须载入到内存中;
然后,程序的执行便开始。
在绝大多数机器里,程序将使用一个运行时堆栈(stack),它用于存储函数的局部变量和返回地址。程序同时也可以使用静态内存(static),存储于静态内存中的变量在程序的整个执行过程将一直保留他们的值。
补充:
假定有一个C程序,他的main函数位于文件main.c,他还有一些函数文件list.c,report.c,在编译和链接这个程序时,应该使用什么命令?
答:gcc main.c list.c report.c
接上题,如果你想使程序链接到parse函数库,应该使用什么命令?
答:-lparse
当一个头文件被修改时,所有包含它的文件都必须重新编译。
小程序:
读取源代码中的字符,判断所有花括号成对出现,不考虑注释字符串内部以及字符常量的花括号。
#include<stdio.h>
#include<stdlib.h>
int main() {
int num; //记录花括号数量;
char ch;
while ( (ch = getchar() != EOF ) {
if ( ch == '{' ) {
num += 1;
}
if ( ch == '}' ) {
if ( num == 0 ) { //这个语句杜绝了当右花括号在前边,左花括号在后边的尴尬境地。
printf("error");
}
else {
num -= 1;
}
}
}
if (num == 0){
printf("right");
}
return EXIT_SUCCESS;
}