2.9 类型检查
在语言中引入类型,使得一个类型定义了一类值的集合,以及对这类值所能进行的操作(运算)的集合。对同一类型数据允许使用这个类型相应的操作,这样,程序员使用的操作是否恰当就可根据数据对象的类型来进行检查,以便写出正确的程序。这种对数据对象的类型及其使用的操作是否匹配的一致性检查称为类型检查(Type Checking)。
语言的类型检查可分为静态检查(Static Checking)和动态检查(Dynamic Checking)。在编译时就能进行的检查称为静态检查;而在运行时才能进行的检查称为动态检查。因为静态检查在编译时完成,所以可用编译器做大量的一致性检查,使程序更正确、更有效。对动态检查的语言而言,程序员在编写程序时可暂不说明数据对象的类型,其类型留待运行时确定,一般需要编译器给出相应的描述符。虽然动态检查的语言编写程序比较方便,程序员不必为类型是否匹配花太多的精力,但程序中变量的类型不明显,程序难读懂,也容易出错,影响程序的可靠性。动态检查还降低了程序执行的效率。
语言可以按类型进行分类。可分为无类型语言、弱类型语言和强类型语言。一个语言没有类型定义,则称为无类型语言,如函数式语言FP和FFP就是无类型语言。一个语言的所有类型检查都可在编译时完成,则称为强类型语言,如ALGOL 68和Ada。若一个语言的类型检查全部或部分要在运行时完成,则称为弱类型语言,例如Pascal语言。下面讨论Pascal是弱类型语言的原因。
(1)Pascal在编译时,不能确定一个过程中的过程参数和子程序参数的类型。例如说明
procedure who_knows(i,j:integer;procedure f); var k :boolean; begin k:=j < i; if k then f(k) else f(j) end;
可能出现一个或两个都不正确的调用,因为与形参f相关联的实参可能类型不匹配,或参数个数不匹配。这些错误在编译时都无法预见,因为错误的发生取决于调用who_knows的实参,所以只有在运行时才能查出。
(2)Pascal的子界不能静态检查。例如在
a:=b + c;
中,若a,b和c都属同一子界类型1..10,那么,在执行之前不能确定b+c的结果值,即不能确定对a的赋值是否越界,只能在运行时计算出b+c的结果值时才能确定。
再如Pascal数组下标类型作为数组类型的一部分,每次访问数组元素时,需要在运行时检查下标是否越界。
(3)由于Pascal变体记录的标识符域可以在运行时改变,因而在编译时检查变体记录的正确使用是不可能的。
(4)Pascal没有严格规定类型的一致性规则,因此它的类型检查基于不稳定的基础,其效果随实现而异。