- 总述
- 预编译
- #define
- 头文件
- 编译
- 语法分析
- 词法分析
- 汇编
- 链接
在ANSI C的任何一种实现中,存在两个不同的环境。一种是翻译环境,第二种是执行环境。我们代码实现需要经过两种大的步骤——编译和运行。以C语言程序为例,我们写完代码后,需要经过编译和运行才能完成整个过程,而编译又包含4个步骤,分别为:预编译,编译,汇编,链接。当连接完成后,就可以执行运行 *** 作。
预编译预处理 *** 作简单的解释就是我们在进行编译(总过程)中进行的准备过程,举个例子,我们在床上准备吃午饭,我们需要做好穿衣服的准备工作才可以去吃饭,那么具体的准备工作有哪些呢?
#define举个例子:
#define MAX 1000 #define reg register //为 register这个关键字,创建一个简短的名字 #define do_forever for(;;) //用更形象的符号来替换一种实现 #define CASE break;case //在写case语句的时候自动把 break写上。 // 如果定义的 stuff过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠(续行符)。 #define DEBUG_PRINT printf("file:%stline:%dt date:%sttime:%sn" , __FILE__,__LINE__ , __DATE__,__TIME__ )
#define是最为常见的预处理符号,我们在初始C语言中曾简单介绍过#define的简单用法,MAX此时是常量,为1000,预编译会将代码中出现的MAX全部替换为1000,而reg则是register的替换,同样预处理会将reg全部替换成register。
关于#define还有一个注意点,就是宏的概念,举个例子:
#define MAX(a, b) ((a)>(b)?(a):(b))
这个宏是用于比较两个数的大小的,那么为什么不用函数来完成这个任务呢?原因有二:
- 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹。
- 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于>来比较的类型。宏是类型无关的。
比较函数和宏:
预处理也会处理头文件,关于头文件,我们会有这样一个问题,就是头文件有时会用<>,有时也会使用"",举个例子:
#include
#include "stdio.h"
当我们用#include "stdio.h"时,预处理会在工程文件夹寻找自己编写的头文件,如果没有发现再去头文件中寻找相对应的库函数,而#include
编译过程就会进行语法分析,词法分析,语义分析,符号分析,我们通常报错等的问题就会出现在这个步骤。
语法分析编译程序的语法分析器以单词符号作为输入,分析单词符号串是否形成符合语法规则的语法单位,如表达式、赋值、循环等,最后看是否构成一个符合要求的程序,按该语言使用的语法规则分析检查每条语句是否有正确的逻辑结构,程序是最终的一个语法单位。编译程序的语法规则可用上下文无关文法来刻画。
词法分析词法分析的任务是对由字符组成的单词进行处理,从左至右逐个字符地对源程序进行扫描,产生一个个的单词符号,把作为字符串的源程序改造成为单词符号串的中间程序。执行词法分析的程序称为词法分析程序或扫描器。
源程序中的单词符号经扫描器分析,一般产生二元式:单词种别;单词自身的值。单词种别通常用整数编码,如果一个种别只含一个单词符号,那么对这个单词符号,种别编码就完全代表它自身的值了。若一个种别含有许多个单词符号,那么,对于它的每个单词符号,除了给出种别编码以外,还应给出自身的值。
汇编过程会形成符号表,将汇编指令转化为二进制指令
汇编指令是在编译中形成,汇编指令是汇编语言中使用的一些 *** 作符和助记符,还包括一些伪指令(如assume,end),汇编指令同机器指令一一对应。每一种CPU都有自己的汇编指令集。我们知道机器只能识别二进制指令,所以汇编过程就是将汇编指令转化为二进制指令。
链接过程就是将之前形成的符号表进行合并,形成一个完成的可执行程序。
整个程序的执行过程就是这样的,当然还有一些细节方面的问题,希望能给大家带来帮助,谢谢各位。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)