文档库 最新最全的文档下载
当前位置:文档库 › C语言第09讲 C语言编译过程

C语言第09讲 C语言编译过程

C语言第09讲 C语言编译过程
C语言第09讲 C语言编译过程

第09讲C语言编译过程

C语言是一种高级语言,并且是编译型的语言。即一个用C写出来的源文件形式的代码,是可以被我们读懂的,但是如果想让机器也能读懂认识,就必须被转换为能够被机器认识的格式--机器语言指令。而完成这个转换工作的,就是C编译器。编译的过程如下图所示。

从上图可以看出,将一个C文本源文件,转换到一个可执行目标程序,一共需要经过四个阶段。

一、预处理阶段

读取c源程序,对其中的伪指令(以#开头的指令)和特殊符号进行处理伪指令主要包括以下四个方面:

二、编译阶段

在该阶段,将文本文件hello.i 翻译成文本文件hello.s ,hello.s是一个汇编语言程序。汇编语言程序中的每条语句都以一种标准的文本格式确切的描述了一条低级机器语言指令。因此,现在虽然有各种各样的编程语言,但编译时,最终都是要被翻译为通用的汇编语言的。

三、汇编阶段

这个时候,汇编器就会将hello.s 翻译为机器语言指令了,并把这些指令打包成可重定位的目标程序格式hello.o 。这个文件是二进制的文件,它的字节编码就是机器语言的指令了,而不是字符了。

汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程。对于被翻译系统处理的每一个C语言源程序,都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。

四、链接阶段

在hello.c程序中,我们调用了标准库里的函数,printf,而printf函数存在于printf.o的目标文件中,这样的话,我们就必须提供某种方法,将printf.o 加入到hello.o中。而这个工作就是由连接器完成的。连接器将所有用到的相关的.o 都链接成一个可执行的目标文件,这个目标文件加载到memory以后,就可以执行了。

由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。

例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。

链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够诶操作系统装入执行的统一整体。

C语言编译过程中的错误分析

C语言编译过程中的错误分析 语言的最大特点是:功能强、使用方便灵活。C编译的程序对语法检查并不象其它高级语言那么严格,这就给编程人员留下“灵活的余地”,但还是由于这个灵活给程序的调试带来了许多不便,尤其对初学C语言的人来说,经常会出一些连自己都不知道错在哪里的错误。看着有错的程序,不知该如何改起,本人通过对C的学习,积累了一些C编程时常犯的错误,写给各位学员以供参考。 1.书写标识符时,忽略了大小写字母的区别。 main() { int a=5; printf("%d",A); } 编译程序把a和A认为是两个不同的变量名,而显示出错信息。C认为大写字母和小写字母是两个不同的字符。习惯上,符号常量名用大写,变量名用小写表示,以增加可读性。 2.忽略了变量的类型,进行了不合法的运算。 main() { float a,b; printf("%d",a%b); } %是求余运算,得到a/b的整余数。整型变量a和b可以进行求余运算,而实型变量则不允许进行“求余”运算。 3.将字符常量与字符串常量混淆。 char c; c="a"; 在这里就混淆了字符常量与字符串常量,字符常量是由一对单引号括起来的单个字符,字符串常量是一对双引号括起来的字符序列。C规定以“”作字符串结束标志,它是由系统自动加上的,所以字符串“a”实际上包含两个字符:‘a'和‘',而把它赋给一个字符变量是不行的。 4.忽略了“=”与“==”的区别。 在许多高级语言中,用“=”符号作为关系运算符“等于”。如在BASIC程序中可以写 if (a=3) then … 但C语言中,“=”是赋值运算符,“==”是关系运算符。如: if (a==3) a=b; 前者是进行比较,a是否和3相等,后者表示如果a和3相等,把b值赋给a。由于习惯问题,初学者往往会犯这样的错误。 5.忘记加分号。 分号是C语句中不可缺少的一部分,语句末尾必须有分号。 a=1 b=2 编译时,编译程序在“a=1”后面没发现分号,就把下一行“b=2”也作为上一行语句的一部分,这就会出现语法错误。改错时,有时在被指出有错的一行中未发

C语言编译器的设计与实现.

C语言编译器的设计与实现 01计算机4班18号任春妍2号陈俊我们设计的编译程序涉及到编译五个阶段中的三个,即词法分析器、语法分析器和中间代码生成器。编译程序的输出结果包括词法分析后的二元式序列、变量名表、状态栈分析过程显示及四元式序列程序,整个编译程序分为三部分: (1) 词法分析部分 (2) 语法分析处理及四元式生成部分 (3) 输出显示部分 一.词法分析器设计 由于我们规定的程序语句中涉及单词较少,故在词法分析阶段忽略了单词输入错误的检查,而将编译程序的重点放在中间代码生成阶段。词法分析器的功能是输入源程序,输出单词符号。我们规定输出的单词符号格式为如下的二元式:(单词种别,单词自身的值) #define ACC -2 #define syl_if 0 #define syl_else 1 #define syl_while 2 #define syl_begin 3 #define syl_end 4 #define a 5 #define semicolon 6 #define e 7 #define jinghao 8 #define s 9 #define L 10 #define tempsy 11 #define EA 12 #define EO 13 #define plus 14 #define times 15 #define becomes 16 #define op_and 17 #define op_or 18 #define op_not 19 #define rop 20 #define lparent 21 #define rparent 22 #define ident 23 #define intconst 24

C语言的编译链接过程的介绍

C语言的编译链接过程的介绍 发布时间:2012-10-2600:00:00来源:中国IT实验室作者:佚名 关键字:C语言 C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接。编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程。链接是把目标文件、操作系统的启动代码和用到的库文件进行组织形成最终生成可执行代码的过程。过程图解如下:

从图上可以看到,整个代码的编译过程分为编译和链接两个过程,编译对应图中的大括号括起的部分,其余则为链接过程。 编译过程 编译过程又可以分成两个阶段:编译和会汇编。 编译 编译是读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,源文件的编译过程包含两个主要阶段: 第一个阶段是预处理阶段,在正式的编译阶段之前进行。预处理阶段将根据已放置在文件中的预处理指令来修改源文件的内容。如 #include指令就是一个预处理指令,它把头文件的内容添加到.cpp文件中。这个在编译之前修改源文件的方式提供了很大的灵活性,以适应不同的计算机和操作系统环境的限制。一个环境需要的代码跟另一个环境所需的代码可能有所不同,因为可用的硬件或操作系统是不同的。在许多情况下,可以把用于不同环境的代码放在同一个文件中,再在预处理阶段修改代码,使之适应当前的环境。 主要是以下几方面的处理:

(1)宏定义指令,如#define a b 对于这种伪指令,预编译所要做的是将程序中的所有a用b替换,但作为字符串常量的a则不被替换。还有#undef,则将取消对某个宏的定义,使以后该串的出现不再被替换。 (2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif 等。 这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译 程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉。 (3)头文件包含指令,如#include"FileName"或者#include等。 在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),同时包含有各种外部符号的声明。采用头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用。因为在需要用到这些定义的C源程序中,只需加上一条#include语句即可,而不必再在此文件中将这些定义重复一遍。预编译程序将把头文件中的定义统统都加入到它所产生的输出文件中,以供编译程序对之进行处理。包含到c源程序中的头文件可以是系统提供的,这些头文件一般被放在 /usr/include目录下。在程序中#include它们要使用尖括号(<>)。

C语言基础知识实例讲解

C语言基础知识:实例讲解 这篇文章旨在让各位对C 有个总体的认识,有看不懂的地方请不必太在意,只要记住就可以了,继续往下学下去就会明白的。 首先请看下面这个简单的C 程序,猜猜它会做些什么。猜不出来也没关系,后面会有详细的解说。 #include int main( void ) /* 一个简单的程序*/ { intnum; /* 声明一个名叫num的变量*/ num = 1; /* 将1 赋值给num */ printf( "This is a simple C program. " ); /* 调用printf函数*/ printf( "My favorite number is %d because it is first. ", num ); return 0; } 在对这个程序进行详细说明之前,我想先请您用编译器把它编译成可执行文件,并且运行,看看运行结果和您的猜想是否一致。如果不懂如何进行编译,请参考以下文章: 下面,我将分两步对这个程序进行详细的讲解。第一步是概要说明,也就是对程序中每一行代码的含义作简单讲解,以帮助您对这个程序有一个大致的理解。第二步是详细说明,也就是程序中的每一行代码进行详细的讲解,以加深您的理解。 一、概要说明 #include <- 把另外一个文件包含进来 这行代码命令编译器把头文件(.h 文件)stdio.h中的内容包含到我们的 程序中。stdio.h是C语言的标准头文件之一,提供对键盘输入和显示输出等的 支持。要使用printf函数,就应该包含这个头文件。顺带一提,stdio代表 standard input/output,也就是标准输入输出的意思。 int main(void) <- 函数头 C 程序由一个或多个函数组成。我们的这个程序只有一个函数:main 函数。圆括号() 表明main 是一个函数;int表明main 函数返回一个整数;void 表明main 函数不接受任何参数。在此,请您紧记,int main(void) 是ISO/ANSI C

C语言编程要点程序的编写和编译

C语言编程要点程序的 编写和编译 Document serial number【LGGKGB-LGG98YT-LGGT8CB-LGUT-

C语言编程要点---第18章程序的编写和编译 第18章程序的编写和编译 本章讲述在编译程序时可以使用的一些技术。在本章中,你将学到专业C程序员在日常编程中所使用的一些技巧。你将会发现,无论是对小项目还是大项目,把源代码分解成几个文件都是很有益处的。在生成函数库时,这一点更为重要。你还将学到可以使用的各种存储模式以及怎样为不同的项目选择不同的存储模式。如果你的程序是由几个源文件组成的,那么你可以通过一个叫MAKE的工具来管理你的项目(project)。你还将学到“.COM"文件和".EXE"文件的区别以及使用“.COM”文件的一个好处。 此外,你还将学到用来解决一个典型的DOS问题的一些技巧,这个问题就是“没有足够的内存来运行DOS程序”。本章还讨论了扩展内存、扩充内存、磁盘交换区、覆盖管理程序和DOS扩展程序的用法,提出了解决"RAM阻塞”这一问题的多种方法,你可以从中选择一种最合适的方法 . 程序是应该写成一个源文件还是多个源文件? 如果你的程序确实很小又很紧凑,那么当然应该把所有的源代码写在一个“.C”文件中。然而,如果你发现自己编写了许多函数(特别是通用函数),那么你就应该把程序分解成几个源文件(也叫做模块)。 把一个程序分解成几个源文件的过程叫做模块化程序设计(modular programming)。模块化程序设计技术提倡用几个不同的结构紧凑的模块一起组成一个完整的程序。例如,如果一个程序中有几种实用函数、屏幕函数和数据库函数,你就可以把这些函数分别放在三个源文件中,分别组成实用模块、屏幕模块和数据库模块。 把函数放在不同的文件中后,你就可以很方便地在其它程序中重复使用那些通用函数。如果你有一些函数还要供其它程序员使用,那么你可以生成一个与别人共享的函数库(见18.9)。 你永远不必担心模块数目“太多”——只要你认为合适,你可以生成很多个模块。一条好的原则就是保持模块的紧凑性.即在同一个源文件中只包含那些在逻辑上与其相关的函数。如果你发现自己把几个没有关系的函数放在了同一个源文件中,那么最好停下来检查一下程序的源代码结构,并且对模块做一下逻辑上的分解。例如,如果要建立一个通信管理数据库,你可能需要有这样一个模块结构: --------------------------------------------------------- 模块名内容 --------------------------------------------------------- Main.c maln()函数 Screen.c 屏幕管理函数 Menus.c 菜单管理函数 Database.c 数据库管理函数 Utility.c 通用功能函数 Contact.c 通信处理函数 Import.c 记录输入函数 Export.c 记录输出函数 Help.c 联机帮助支持函数 ---------------------------------------------------------- 请参见: 18.10 如果一个程序包含多个源文件,怎样使它们都能正常工作? . 各种存储模式之间有什么区别? DOS用一种段地址结构来编址计算机的内存,每一个物理内存位置都有一个可通过段地址一偏移量的方式来访问的相关地址。为了支持这种段地址结构,大多数C编译程序都允许你用以下6种存储模式来创建程序: ----------------------------------------------------------------------- 存储模式限制所用指针 ----------------------------------------------------------------------- Tiny(微) 代码、数据和栈一64KB Near

编译原理C语言词法分析器

编译原理 C语言词法分析器 一、实验题目 编制并调试C词法分析程序。 a.txt源代码: ?main() { int sum=0 ,it=1;/* Variable declaration*/ if (sum==1) it++; else it=it+2; }? 设计其词法分析程序,能识别出所有的关键字、标识符、常数、运算符(包括复合运算符,如++)、界符;能过滤掉源程序中的注释、空格、制表符、换行符;并且能够对一些词法规则的错误进行必要的处理,如:标识符只能由字母、数字和下划线组成,且第一个字符必须为字母或下划线。实验要求:要给出所分析语言的词法说明,相应的状态转换图,单词的种别编码方案,词法分析程序的主要算法思想等。 二、实验目的 1、理解词法分析在编译程序中的作用; 2、掌握词法分析程序的实现方法和技术; 3、加深对有穷自动机模型的理解。 三、主要函数 四、设计 1. 主函数 void main ( )

2. 初始化函数 void load ( ) 3. 保留字及标识符判断函数 void char_search(char *word) 4. 整数类型判断函数 void inta_search(char *word) 5. 浮点类型判断函数 void intb_search(char *word)

6. 字符串常量判断函数 void cc_search(char *word) 7. 字符常量判断函数 void c_search(char *word) 同4、5函数图 8.主扫描函数 void scan ( ) 五、关键代码 #include <> #include <> #include <> char *key0[]={"

C语言编译过程总结详解

C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接。编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程。链接是把目标文件、操作系统的启动代码和用到的库文件进行组织形成最终生成可执行代码的过程。过程图解如下: 从图上可以看到,整个代码的编译过程分为编译和链接两个过程,编译对应图中的大括号括起的部分,其余则为链接过程。 编译过程 编译过程又可以分成两个阶段:编译和会汇编。 编译 编译是读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,源文件的编译过程包含两个主要阶段: 第一个阶段是预处理阶段,在正式的编译阶段之前进行。预处理阶段将根据已放置在文件中的预处理指令来修改源文件的内容。如#include指令就是一个预处理指令,它把头文件的内容添加到.cpp文件中。这个在编译之前修改源文件的方式提供了很大的灵活性,以适应不同的计算机和操作系统环境的限制。一个环境需要的代码跟另一个环境所需的代码可能有所不同,因为可用的硬件或操作系统是不同的。在许多情况下,可以把用于不同环境的代码放在同一个文件中,再在预处理阶段修改代码,使之适应当前的环境。 主要是以下几方面的处理: (1)宏定义指令,如 #define a? b 对于这种伪指令,预编译所要做的是将程序中的所有a用b替换,但作为字符串常量的 a 则不被替换。还有 #undef,则将取消对某个宏的定义,使以后该串的出现不再被替换。 (2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。 这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉。 (3)头文件包含指令,如#include "FileName"或者#include 等。 在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),同时包含有各种外部符号的声明。采用头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用。因为在需要用到这些定义的C源程序中,只需加上一条#include语句即可,而不必再在此文件中将这些定义重复一遍。预编译程序将把头文件中的定义统统都加入到它所产生的输出文件中,以供编译程序对之进行处理。包含到c源程序中的头文件可以是系统提供的,这些头文件一般被放在 /usr/include目录下。在程序中#include它们要使用尖括号(< >)。另外开发人员也可以定义自己的头文件,这些文件一般与c源程序放在同一目录下,此时在#include中要用双引号("")。 (4)特殊符号,预编译程序可以识别一些特殊的符号。 例如在源程序中出现的LINE标识将被解释为当前行号(十进制数),FILE则被解释为当前被编译的C源程序的名称。预编译程序对于在源程序中出现的这些串将用合适的值进行替换。 预编译程序所完成的基本上是对源程序的“替代”工作。经过此种替代,生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件。这个文件的含义同没有经过预处理的源文件是相同的,但内容有所不同。下一步,此输出文件将作为编译程序的输出而被翻译成为机器指令。 第二个阶段编译、优化阶段,经过预编译得到的输出文件中,只有常量;如数字、字符串、变量的定义,以及C语言的关键字,如main,if,else,for,while,{,}, +,-,*,\等等。

C语言作业题

能将高级语言编写的源程序转换成目标程序的是______。 A) 编辑程序B) 编译程序C) 解释程序D) 链接程序 [A] [B] [C] [D] 以下选项中合法的用户标识符是______。 A) long B) _2Test C) 3Dmax D) A.dat [A] [B] [C] [D] 以下叙述正确的是 A) 可以把define和if定义为用户标识符 B) 可以把define定义为用户标识符,但不能把if定义为用户标识符 C) 可以把if定义为用户标识符,但不能把define定义为用户标识符 D) define和if都不能定义为用户标识符 [A] [B] [C] [D] 以下叙述正确的是 A) C语言比其他语言高级 B) C语言可以不用编译就能被计算机识别执行 C) C语言以接近英语国家的自然语言和数学语言作为语言的表达形式 D) C语言出现的最晚、具有其他语言的一切优点 [A] [B] [C] [D] 在一个C语言程序中 A) main函数必须出现在所有函数之前 B) main函数必须出现在所有函数之后 C) main函数可以在任何地方出现 D) main函数必须出现在固定位置 [A] [B] [C] [D] 一个C语言程序是由_______组成的。 A) 一个主程序和若干子程序 B) 若干子程序 C) 函数 D) 若干过程 [A] [B] [C] [D] 以下叙述中正确的是() A) C语言的源程序不必通过编译就可以直接运行 B) C语言中的每条可执行语句最终都将被转换成二进制的机器指令

C) C源程序经编译形成的二进制代码可以直接运行 D) C语言中的函数不可以单独进行编译 [A] [B] [C] [D] 下列关于C语言用户标识符的叙述中正确的是 A) 用户标识符中可以出现下划线和数字,它们都可以放在用户标识符的开头 B) 用户标识符中可以出现下划线,但不可以放在用户标识符的开头 C) 用户标识符中不可以出现中划线,但可以出现下划线 D) 用户标识符中可以出现下划线和中划线(减号) [A] [B] [C] [D] 以下说法中正确的是 A)C语言程序总是从第一个定义的函数开始执行 B)C语言程序中,要调用的函数必须在main()函数中定义 C)C语言程序总是从main()函数开始执行 D)C语言程序中的main()函数必须放在程序的开始部分 [A] [B] [C] [D] 默认情况下,一个C程序的执行是从 A)本程序的main函数开始,到main函数结束 B)本程序文件的第一个函数开始,到本程序文件的最后一个函数结束 C)本程序的main函数开始,到本程序文件的最后一个函数结束 D)本程序文件的第一个函数开始,到本程序main函数结束 [A] [B] [C] [D] C语言编程整个操作的过程是 A)编辑、编译、链接、执行 B)编译、编辑、链接、执行 C)链接、编译、编辑、执行 D)编辑、链接、编译、执行 [A] [B] [C] [D] 下列说法不正确的是 A)链接操作将生成扩展名为.lnk的文件 B)编辑过程将生成扩展名为.cpp或.c的文件 C)编译过程将生成扩展名为.obj的文件 C)C编程最终要生成扩展名为.exe的文件

C语言条件编译及编译预处理阶段

C语言条件编译及编译预处理阶段 一、C语言由源代码生成的各阶段如下: C源程序->编译预处理->编译->优化程序->汇编程序->链接程序->可执行文件其中编译预处理阶段,读取c源程序,对其中的伪指令(以#开头的指令)和特殊符号进行处理。或者说是扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器。预处理过程先于编译器对源代码进行处理。 在C 语言中,并没有任何内在的机制来完成如下一些功能:在编译时包含其他源文件、定义宏、根据条件决定编译时是否包含某些代码。要完成这些工作,就需要使用预处理程序。尽管在目前绝大多数编译器都包含了预处理程序,但通常认为它们是独立于编译器的。预处理过程读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行响应的转换。预处理过程还会删除程序中的注释和多余的空白字符。 二、伪指令(或预处理指令)定义 预处理指令是以#号开头的代码行。#号必须是该行除了任何空白字符外的第一个字符。#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。下面是部分预处理指令: 指令用途 # 空指令,无任何效果 #include 包含一个源代码文件 #define定义宏 #undef取消已定义的宏 #if如果给定条件为真,则编译下面代码 #ifdef 如果宏已经定义,则编译下面代码 #ifndef 如果宏没有定义,则编译下面代码 #elif如果前面的#if给定条件不为真,当前条件为真,则编译下面代码, 其实就是elseif的简写 #endif结束一个#if……#else条件编译块 #error停止编译并显示错误信息 三、预处理指令主要包括以下四个方面: 1、宏定义指令 宏定义了一个代表特定内容的标识符。预处理过程会把源代码中出现的宏标识符替换成宏定义时的值。宏最常见的用法是定义代表某个值的全局符号。宏的第二种用法是定义带参数的宏(宏函数),这样的宏可以象函数一样被调用,但它是在调用语句处展开宏,并

编译原理课程设计____C语言编译器的实现

南华大学 编译原理课程设计名:编译代生 成器设计 专业计算机科学与技术 学生姓名熊浩斌 班级计算机01班 学号 20109440114 指导老师陈星 实验地点 8栋 2-209 完成日期:2013.6.2

一、课程设计的目的 编译原理课程兼有很强的理论性和实践性,是计算机专业的一门非常重要的专业基础课程,它在系统软件中占有十分重要的地位,是计算机专业学生的一门主修课。为了让学生能够更好地掌握编译原理的基本理论和编译程序构造的基本方法和技巧,融会贯通本课程所学专业理论知识,提高他们的软件设计能力,特设定该课程的课程设计,通过设计一个简单的PASCAL语言(EL语言)的编译程序,提高学生设计程序的能力,加深对编译理论知识的理解与应用。 二、课程设计的要求 1、明确课程设计任务,复习编译理论知识,查阅复印相关的编译资料。 2、按要求完成课程设计内容,课程设计报告要求文字和图表工整、思路清晰、算法正 确。 3、写出完整的算法框架。 4、编写完整的编译程序。 三、课程设计的内容 课程设计是一项综合性实践环节,是对平时实验的一个补充,课程设计内容包括课程的主要理论知识,但由于编译的知识量较复杂而且综合性较强,因而对一个完整的编译程序不适合平时实验。通过课程设计可以达到综合设计编译程序的目的。本课程的课程设计要求学生编写一个完整的编译程序,包括词法分析器、语法分析器以及实现对简单程序设计语言中的逻辑运算表达式、算术运算表达式、赋值语句、IF语句、While语句以及do…while语句进行编译,并生成中间代码和直接生汇编指令的代码生成器。 四、总体设计方案及详细设计 总体设计方案: 1.总体模块

C语言基础知识(详细版)

C语言程序的结构认识 用一个简单的c 程序例子,介绍c 语言的基本构成、格式、以及良好的书写风格,使小伙伴对 c 语言有个 初步认识。 例1:计算两个整数之和的c 程序: #include main() { int a,b,sum; /* 定义变量a,b ,sum 为整型变量*/ a=20; /* 把整数20 赋值给整型变量a*/ b=15; /* 把整数15 赋值给整型变量b*/ sum=a+b; /* 把两个数之和赋值给整型变量sum*/ printf( “ a=%d,b=%d,sum=%d\n” ,a,b,sum); /* 把计算结果输出到显示屏上*/ } 重点说明: 1、任何一个c 语言程序都必须包括以下格式: main() { } 这是c 语言的基本结构,任何一个程序都必须包含这个结构。括号内可以不写任何内容,那么该程序将不执行任何结果。 2、main() - 在c 语言中称之为“主函数” ,一个c 程序有且仅有一个main 函数,任何一个c 程序总是从 main 函数开始执行,main 函数后面的一对圆括号不能省略。 3、被大括号{ }括起来的内容称为main 函数的函数体,这部分内容就是计算机要执行的内容。 4、在{ }里面每一句话后面都有一个分号(; ),在c 语言中,我们把以一个分号结尾的一句话叫做一个 c 语 言的语句,分号是语句结束的标志。 5、printf( “ a=%d,b=%d,sum=%d\n” ,a,b,sum); 通过执行这条c 语言系统提供给我们直接使用的屏幕输出 函数,用户即可看到运行结果,本程序运行后,将在显示器上显示如下结果: a=20,b=15,sum=35 6、#include 注意:(1)以#号开头 (2)不以分号结尾这一行没有分号,所以不是语句,在c 语言中称之为命令行,或者叫做“预编译处理命令” 。 7、程序中以/* 开头并且以*/ 结尾的部分表示程序的注释部分,注释可以添加在程序的任何位置,为了提高程序的可读性而添加,但计算机在执行主函数内容时完全忽略注释部分,换而言之就是计算机当做注释部分不存在于主函数中。 C程序的生成过程 C程序是先由源文件经编译生成目标文件,然后经过连接生成可执行文件。 源程序的扩展名为.c ,目标程序的扩展名为.obj , 可执行程序的扩展名为.exe 。

编译原理课程设计----C语言编译器的实现

$ 编译原理课程设计报告 设计题目编译代码生成器设计 、 学生姓名 班级 学号 指导老师 成绩 `

一、课程设计的目的 编译原理课程兼有很强的理论性和实践性,是计算机专业的一门非常重要的专业基础课程,它在系统软件中占有十分重要的地位,是计算机专业学生的一门主修课。为了让学生能够更好地掌握编译原理的基本理论和编译程序构造的基本方法和技巧,融会贯通本课程所学专业理论知识,提高他们的软件设计能力,特设定该课程的课程设计,通过设计一个简单的PASCAL语言(EL语言)的编译程序,提高学生设计程序的能力,加深对编译理论知识的理解与应用。 二、课程设计的要求 1、明确课程设计任务,复习编译理论知识,查阅复印相关的编译资料。 2、按要求完成课程设计内容,课程设计报告要求文字和图表工整、思路清晰、算法正 确。 3、@ 4、写出完整的算法框架。 5、编写完整的编译程序。 三、课程设计的内容 课程设计是一项综合性实践环节,是对平时实验的一个补充,课程设计内容包括课程的主要理论知识,但由于编译的知识量较复杂而且综合性较强,因而对一个完整的编译程序不适合平时实验。通过课程设计可以达到综合设计编译程序的目的。本课程的课程设计要求学生编写一个完整的编译程序,包括词法分析器、语法分析器以及实现对简单程序设计语言中的逻辑运算表达式、算术运算表达式、赋值语句、IF语句、While语句以及do…while语句进行编译,并生成中间代码和直接生汇编指令的代码生成器。 四、总体设计方案及详细设计 总体设计方案: 1.总体模块

【 2. \ 详细设计: 界面导入设计 (1)一共三个选项: ①choice 1--------cifafenxi ②choice 2--------yufafenxi ③choice 3--------zhongjiandaima (2)界面演示 } 图一

C语言编译和连接

一、编译 编译(compilation,compile) 1、利用编译程序从源语言编写的源程序产生目标程序的过程。 2、用编译程序产生目标程序的动作。 编译就是把高级语言变成计算机可以识别的2进制语言,计算机只认识1和0,编译程序把人们熟悉的语言换成2进制的。 编译程序把一个源程序翻译成目标程序的工作过程分为五个阶段:词法分析;语法分析;中间代码生成;代码优化;目标代码生成。主要是进行词法分析和语法分析,又称为源程序分析,分析过程中发现有语法错误,给出提示信息。 (1)词法分析 词法分析的任务是对由字符组成的单词进行处理,从左至右逐个字符地对源程序进行扫描,产生一个个的单词符号,把作为字符串的源程序改造成为单词符号串的中间程序。执行词法分析的程序称为词法分析程序或扫描器。 源程序中的单词符号经扫描器分析,一般产生二元式:单词种别;单词自身的值。单词种别通常用整数编码,如果一个种别只含一个单词符号,那么对这个单词符号,种别编码就完全代表它自身的值了。若一个种别含有许多个单词符号,那么,对于它的每个单词符号,除了给出种别编码以外,还应给出自身的值。 词法分析器一般来说有两种方法构造:手工构造和自动生成。手工构造可使用状态图进行工作,自动生成使用确定的有限自动机来实现。 (2)语法分析 编译程序的语法分析器以单词符号作为输入,分析单词符号串是否形成符合语法规则的语法单位,如表达式、赋值、循环等,最后看是否构成一个符合要求的程序,按该语言使用的语法规则分析检查每条语句是否有正确的逻辑结构,程序是最终的一个语法单位。编译程序的语法规则可用上下文无关文法来刻画。 语法分析的方法分为两种:自上而下分析法和自下而上分析法。自上而下就是从文法的开始符号出发,向下推导,推出句子。而自下而上分析法采用的是移进归约法,基本思想是:用一个寄存符号的先进后出栈,把输入符号一个一个地移进栈里,当栈顶形成某个产生式的一个候选式时,即把栈顶的这一部分归约成该产生式的左邻符号。 (3)中间代码生成 中间代码是源程序的一种内部表示,或称中间语言。中间代码的作用是可使编译程序的结构在逻辑上更为简单明确,特别是可使目标代码的优化比较容易实现。中间代码即为中间语言程序,中间语言的复杂性介于源程序语言和机器语言之间。中间语言有多种形式,常见的有逆波兰记号、四元式、三元式和树。 (4)代码优化 代码优化是指对程序进行多种等价变换,使得从变换后的程序出发,能生成更有效的目标代码。所谓等价,是指不改变程序的运行结果。所谓有效,主要指目标代码运行时间较短,以及占用的存储空间较小。这种变换称为优化。 有两类优化:一类是对语法分析后的中间代码进行优化,它不依赖于具体的计算机;另一类是在生成目标代码时进行的,它在很大程度上依赖于具体的计算机。对于前一类优化,根据它所涉及的程序范围可分为局部优化、循环优化和全局优化三个不同的级别。 (5)目标代码生成

C语言中的条件编译

C语言中的条件编译 一般情况下,源程序中所有的行都参加编译。但是有时希望对其中一部分内容只在满足一定条件下才进行编译,即对一部分内容指定编译条件,这就是“条件编译”(conditional compile 预处理过程扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器。可见预处理过程先于编译器对源代码进行处理。 在C语言中,并没有任何内在的机制来完成如下一些功能:在编译时包含其他源文件、定义宏、根据条件决定编译时是否包含某些代码。要完成这些工作,就需要使用预处理程序。尽管在目前绝大多数编译器都包含了预处理程序,但通常认为它们是独立于编译器的。预处理过程读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行响应的转换。预处理过程还会删除程序中的注释和多余的空白字符。 预处理指令是以#号开头的代码行。#号必须是该行除了任何空白字符外的第一个字符。#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。下面是部分预处理指令: 指令用途 #空指令,无任何效果 #include包含一个源代码文件 #define定义宏 #undef取消已定义的宏 #if如果给定条件为真,则编译下面代码 #ifdef如果宏已经定义,则编译下面代码 #ifndef如果宏没有定义,则编译下面代码 #elif如果前面的#if给定条件不为真,当前条件为真,则编译下面代码 #endif结束一个#if……#else条件编译块 #error停止编译并显示错误信息 一、文件包含 #include预处理指令的作用是在指令处展开被包含的文件。包含可以是多重的,也就是说一个被包含的文件中还可以包含其他文件。标准C编译器至少支持八重嵌套包含。 预处理过程不检查在转换单元中是否已经包含了某个文件并阻止对它的多次包含。这样就可以在多次包含同一个头文件时,通过给定编译时的条件来达到不同的效果。例如: #define AAA #include"t.c" #undef AAA #include"t.c" 为了避免那些只能包含一次的头文件被多次包含,可以在头文件中用编译时条件来进行控制。例如: /*my.h*/ #ifndef MY_H #define MY_H

C语言第四讲 程序的控制结构

实验五程序的控制结构 实验目的 (1)理解程序的控制结构 (2)掌握if语句实现选择结构 (3)掌握函数中的if与return语句 (4)掌握计数型循环结构的构建 (5)掌握while语句和for语句 实验内容 任务一:改错分段函数的计算 1.打开程序文件error1-8.cpp。 #include int main(void) { double x, printf("Enter x: \n"); scanf("=%f", x); if(x = 10){ y = 1 / x } else (x != 10){ y = x; } printf("f(%.2f) = %.lf\n" x y); return 0; } 2. 程序的功能是输入x,如果x等于10,y等于1/x,否则y等于x。请根据VC2012的错误信息改正错误,使程序可以运行。 3. 测试运行结果 ?Enter x:10 ?f(10.00)=0.1 ?Enter x:0.23 ?f(0.23)=0.2

任务二:改错两数排序 1.打开程序文件error1-9.cpp。 #include int main(void) { double a,b,c; printf("Enter a,b: \n"); scanf("%lf,%lf", a,b); if(a>b) c=a;a=b;b=c; printf("a= %lf,b=%lf\n" a,b); return 0; } 2. 程序的功能是输入两数到变量a,b,比较a、b,使a中存放较小数,b中存放较大数。请根据VC6的compile和link错误信息改正错误,使程序可以运行。 3. 测试运行结果 ?Enter a,b:24.5,14.5 ?a=14.5 b=24.5 任务三:改错输出温度转化表 1.打开程序文件error1-10.cpp #include int main(void) { int fahr , lower, upper; /* fahr表示华氏度*/ double celsius; /* celsius表示摄氏度*/ lower = 30; /* 变量lower 给定转换范围的下限*/ upper = 35; /* 变量upper 给定转换范围的上限*/ printf("fahr celsius\n"); /* 显示表头*/ /* 温度转换*/ for (fahr = lower , fahr <= upper, fahr ++) ; celsius = 5 /9 * (fahr - 32.0); printf("%3.0f %6.1f\n", fahr, celsius);

C语言exe文件编译过程

用简单C程序分析DOS下的EXE文件 DOS下的EXE文件格式比较简单,所以咱们先把Windows下的那个复杂的EXE文件放一边,挑个软柿子捏捏(以下EXE如不特殊说明均指DOS下的EXE文件格式)。 其实网上关于EXE格式的说明很多,大都是哗啦列出大批格式说明,看得人是头晕脑胀的。等自己搞懂了,总觉的其中个别说明不太精确导致自己误解浪费了不少时间。所以,咱们要自己动手去实践一下,边动手边理解就容易多了。至于本次分析为什么用C,这个嘛,咱们随便分析一下C语言与汇编的联系,尤其是子程序的调用,这跟什么什么标准有关。好,废话少说,切入正题! 1.软件准备 ①既然跟DOS有关,得有个DOS系统吧。现在盛行虚拟机,安装简单并且系统崩溃的话跟自己电脑的硬件没关联,安全方便。至于怎么安装,请参阅本人拙文: VMware上安装MS-DOS 6.22之一:基本系统的安装 VMware上安装MS-DOS 6.22之二:光驱驱动及其他的安装 ②另外还要安装上Turbo C。初学C的大概都用过这个东东吧。安装在DOS上吧。我用的是Turbo C++ 3。 ③还得有个能查看文件16进制的软件。例如UltraEdit。 2.生成EXE文件 我们要从最简单的分析起,所以C程序尽量简单,只包含一个子程序调用。如下 怎么样,够简单的吧。编译链接生成EXE文件。

3.小样,来吧,让我分析分析你 ①用UltraEdit打开生成的EXE文件如下图(只截取了开头一部分) 下面着重说几个重要的偏移。 ②上图的被红框圈的两个字母看见了没,这个就是EXE文件的标示,它占用了文件最开头的俩字节。可能你纳闷了为什么用MZ呢?哈哈,自己上网查查吧。 ③再往下看,在偏移02-03h的地方存放了000C(不要告诉我存放的是0C00),在偏移04-04h的地方存放了0009(请不要替我纠“错”)。通过这两个数据可以计算出文件大小,在这里0009指出该文件用了9个块(1个块是512B),000C指出最后一个块(第9个块)没有用完只用了000C个字节。明白了吧。来,实际计算一下(9﹣1)×512B=4096,再加上12(000Ch)等于4108B。跟DOS里显示的一样。 ④偏移06-07h处为重定向项目的个数。什么叫重定向呢,简单的说就是:EXE文件必须要加载到内存中才能执行,但是文件中数据的偏移地址跟内存中偏移是不一样的,重定向就是达到重新修改偏移的目的。可以看出我们这个文件中重定向项的个数为1。在这里我们也应该看一下偏移18-19h处的数据,它指出了第一个重定向项目在本文件中的偏移,在本文件中为003Eh。即,在本文件003Eh偏移处存放了第一个重定向项目的内容,它的结构体声明为: struct EXE_RELOC { unsigned short offset; unsigned short segment; }; ⑤偏移08-09h处:该处数据指出了EXE头部大小,一般EXE头部后面紧跟着的就是程序数据了。本文件中为0020h,注意它的单位是节,一个节为16个字节,也即程序数据开始于文件偏移200h处。 ⑥偏移0A-0Bh处:该处数据指出了运行该程序所需的最小内存,如果小于这个内存,程序将不会被加载执行。 ⑦偏移0C-0Dh处:该处数据指出了运行该程序所需的最大内存,一般为FFFFh。 ⑧偏移0E-0Fh处:堆栈段在装入模块中的偏移,本文件中为:00E5h 偏移10-11h处:SP初始值,本文件中为:0080h 即SS:SP=00E5:0080 ⑨偏移14-15h处:IP初始值,本文件中为:0 偏移16-17h处:CS在装入模块中的偏移,本文件中为:0 我们看看实际加载到内存中是SS、SP和CS、IP是如何分配的

C语言编译全过程

编译的概念:编译程序读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言,并且按照操作系统对可执行文件格式的要求链接生成可执行程序。 编译的完整过程:C源程序-->预编译处理(.c)-->编译、优化程序(.s、.asm)-->汇编程序(.obj、.o、.a、.ko)-->链接程序(.exe、.elf、.axf等) 1. 编译预处理 读取c源程序,对其中的伪指令(以#开头的指令)和特殊符号进行处理 伪指令主要包括以下四个方面: (1)宏定义指令,如#define Name TokenString,#undef等。 对于前一个伪指令,预编译所要做的是将程序中的所有Name用TokenString替换,但作为字符串常量的Name则不被替换。对于后者,则将取消对某个宏的定义,使以后该串的出现不再被替换。 (2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。 这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉 (3)头文件包含指令,如#include "FileName"或者#include 等。 在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),同时包含有各种外部符号的声明。 采用头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用。因为在需要用到这些定义的C源程序中,只需加上一条#include语句即可,而不必再在此文件中将这些定义重复一遍。预编译程序将把头文件中的定义统统都加入到它所产生的输出文件中,以供编译程序对之进行处理。 包含到c源程序中的头文件可以是系统提供的,这些头文件一般被放在/usr/include目录下。在程序中#include它们要使用尖括号(< >)。另外开发人员也可以定义自己的头文件,这些文件一般与c源程序放在同一目录下,此时在#include中要用双引号("")。 (4)特殊符号,预编译程序可以识别一些特殊的符号。 例如在源程序中出现的LINE标识将被解释为当前行号(十进制数),FILE则被解释为当前被编译的C源程序的名称。预编译程序对于在源程序中出现的这些串将用合适的值进行替换。 预编译程序所完成的基本上是对源程序的“替代”工作。经过此种替代,生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件。这个文件的含义同没有经过预处理的源文件是相同的,但内容有所不同。下一步,此输出文件将作为编译程序的输出而被翻译成为机器指令。 2. 编译、优化阶段 经过预编译得到的输出文件中,只有常量;如数字、字符串、变量的定义,以及C语

相关文档
相关文档 最新文档