C语言编译和连接
- 格式:pdf
- 大小:135.17 KB
- 文档页数:4
一、编译
编译(compilation,compile)
1、利用编译程序从源语言编写的源程序产生目标程序的过程。
2、用编译程序产生目标程序的动作。
编译就是把高级语言变成计算机可以识别的2进制语言,计算机只认识1和0,编译程序把人们熟悉的语言换成2进制的。
编译程序把一个源程序翻译成目标程序的工作过程分为五个阶段:词法分析;语法分析;中间代码生成;代码优化;目标代码生成。
主要是进行词法分析和语法分析,又称为源程序分析,分析过程中发现有语法错误,给出提示信息。
(1)词法分析
词法分析的任务是对由字符组成的单词进行处理,从左至右逐个字符地对源程序进行扫描,产生一个个的单词符号,把作为字符串的源程序改造成为单词符号串的中间程序。
执行词法分析的程序称为词法分析程序或扫描器。
源程序中的单词符号经扫描器分析,一般产生二元式:单词种别;单词自身的值。
单词种别通常用整数编码,如果一个种别只含一个单词符号,那么对这个单词符号,种别编码就完全代表它自身的值了。
若一个种别含有许多个单词符号,那么,对于它的每个单词符号,除了给出种别编码以外,还应给出自身的值。
词法分析器一般来说有两种方法构造:手工构造和自动生成。
手工构造可使用状态图进行工作,自动生成使用确定的有限自动机来实现。
(2)语法分析
编译程序的语法分析器以单词符号作为输入,分析单词符号串是否形成符合语法规则的语法单位,如表达式、赋值、循环等,最后看是否构成一个符合要求的程序,按该语言使用的语法规则分析检查每条语句是否有正确的逻辑结构,程序是最终的一个语法单位。
编译程序的语法规则可用上下文无关文法来刻画。
语法分析的方法分为两种:自上而下分析法和自下而上分析法。
自上而下就是从文法的开始符号出发,向下推导,推出句子。
而自下而上分析法采用的是移进归约法,基本思想是:用一个寄存符号的先进后出栈,把输入符号一个一个地移进栈里,当栈顶形成某个产生式的一个候选式时,即把栈顶的这一部分归约成该产生式的左邻符号。
(3)中间代码生成
中间代码是源程序的一种内部表示,或称中间语言。
中间代码的作用是可使编译程序的结构在逻辑上更为简单明确,特别是可使目标代码的优化比较容易实现。
中间代码即为中间语言程序,中间语言的复杂性介于源程序语言和机器语言之间。
中间语言有多种形式,常见的有逆波兰记号、四元式、三元式和树。
(4)代码优化
代码优化是指对程序进行多种等价变换,使得从变换后的程序出发,能生成更有效的目标代码。
所谓等价,是指不改变程序的运行结果。
所谓有效,主要指目标代码运行时间较短,以及占用的存储空间较小。
这种变换称为优化。
有两类优化:一类是对语法分析后的中间代码进行优化,它不依赖于具体的计算机;另一类是在生成目标代码时进行的,它在很大程度上依赖于具体的计算机。
对于前一类优化,根据它所涉及的程序范围可分为局部优化、循环优化和全局优化三个不同的级别。
(5)目标代码生成
目标代码生成是编译的最后一个阶段。
目标代码生成器把语法分析后或优化后的中间代码变换成目标代码。
目标代码有三种形式:
①可以立即执行的机器语言代码,所有地址都重定位;
②待装配的机器语言模块,当需要执行时,由连接装入程序把它们和某些运行程序连接起来,转换成能执行的机器语言代码;
③汇编语言代码,须经过汇编程序汇编后,成为可执行的机器语言代码。
目标代码生成阶段应考虑直接影响到目标代码速度的三个问题:一是如何生成较短的目标代码;二是如何充分利用计算机中的寄存器,减少目标代码访问存储单元的次数;三是如何充分利用计算机指令系统的特点,以提高目标代码的质量。
二、连接
把目标文件和用到的库文件汇合起来,把函数的定义和调用通过地址编译连接起
连接时的错误类型:
初学者在学习VC++的过程中,遇到的LNK2001错误的错误消息主要为:unresolved external symbol“symbol”(不确定的外部“符号”)。
如果连接程序不能在所有的库和目标文件内找到所引用的函数、变量或标签,将产生此错误消息。
一般来说,发生错误的原因有两个:一是所引用的函数、变量不存在、拼写不正确或者使用错误;其次可能使用了不同版本的连接库。
以下是可能产生LNK2001错误的原因:
一.由于编码错误导致的LNK2001。
1.不相匹配的程序代码或模块定义(.DEF)文件能导致LNK2001。
例如,如果在C++源文件内声明了一变量“var1”,却试图在另一文件内以变量“VAR1”访问该变量,将发生该错误。
2.如果使用的内联函数是在.CPP文件内定义的,而不是在头文件内定义将导致LNK2001错误。
3.调用函数时如果所用的参数类型同函数声明时的类型不符将会产生
LNK2001。
4.试图从基类的构造函数或析构函数中调用虚拟函数时将会导致LNK2001。
5.要注意函数和变量的可公用性,只有全局变量、函数是可公用的。
静态函数和静态变量具有相同的使用范围限制。
当试图从文件外部访问任何没有在该文件内声明的静态变量时将导致编译错误或LNK2001。
函数内声明的变量(局部变量)只能在该函数的范围内使用。
三、数组和指针的差别
a)数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。
数组
名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。
数组初始化是在编译阶段进行的,所以要知
道具体的数组的大小,便于分配空间。
b)指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常
用指针来操作动态内存。
指针远比数组灵活,但也更危险.
四、编译时的相关工作
编译时:程序生成机器码,类的对象变量(包括数组)是在编译时分配存储空间,这时候分配的是相对的地址。
程序运行时:函数进行动态分配的,分配临时的内存单元,此时分配绝对地址。
全局变量是在程序开始时分配的。
这和可执行文件格式也有关,PE是分代码段、数据段等存储文件信息。
其中的外部函数等的地址都是程序内相对地址,是虚拟地址。
当windows载入程序时,他根据文件格式(windows中就是PE)将程序装入内存空间,也就是实现相对地址到绝对地址的映射。
五、。