程序设计语言与编译
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.10 类型转换

类型转换是将一种类型的值转换为另一种类型的值。

我们曾经指出,表达式a+b中的运算符是一种超载,它可以是定点加,也可以是浮点加。当a和b同为整型,它就是定点加;当a和b同为实型,它就是浮点加。那么,a和b一个是整型,一个是实型时又代表什么加呢?通常,每种语言都会做出自己的规定,使a和b转换成相同的类型(或者同为整型,或者同为实型)。将一个类型的值转换成另一个类型的值,在程序设计中经常出现,通常称为类型转换(Type Conversion)。

类型转换可分为拓展(Widening)和收缩(Narrowing)两类。若转换之前的每一个值都在转换之后的类型中有相应的值,即转换之后的类型值的集合包含转换之前类型值的集合,这样的转换称为拓展,例如整数到实数的转换。反之,若转换之前类型值的集合包含转换之后类型值的集合,则称为收缩,如实数到整数的转换。收缩可能导致某些信息的丢失。在PL/1语言中,由实数到整数的收缩采用截断,而Pascal从实数到整数的转换使用舍入法进行收缩。

在某些语言中,这种类型转换的要求和规则都是隐式的,它由编译器自动生成有关转换代码来实现。这些代码根据对象的类型和语言给出的类型优先规则来确定。例如,FORTRAN类型优先级别是

          COMPLEX > DOUBLE PRECISION > REAL > INTEGER

若给定操作a op b,那么在op执行之前,低级的类型向高级的类型转换。一般来说,语言对基本数据类型提供了适当的类型转换,而对复合类型或用户定义类型不提供类型的转换,由程序员自行解决。Pascal中对基本数据类型仅允许从整数到实数的转换,以及子界类型与整数间的拓展与收缩。因此在

          var r :real;
            i :integer;
          i:=r;

中的赋值语句是非法的,必须以显式的方法写成

          i:=frunc(r)

          i:=round(r)

使实数r截断或舍入成整数后再赋值给整型变量i。

ALGOL 68对类型转换给出了完全的、形式化的隐式转换规则。它一共提出了6种隐式强制转换规则,用以强制将一种类型的值转换到另一种类型的值。这种自动转换削弱了编译器对程序的类型检查能力,因为它使变量的类型说明失去部分作用,掩盖了一些程序员类型使用中的错误。

C++语言允许的类型转换有4种:

标准类型➝标准类型

标准类型➝类类型

类类型➝标准类型

类类型➝类类型

标准类型为除class、struct和union类型(即所有的类类型)外的其他所有类型。对于标准类型,C++提供了两种类型转换:隐式类型转换和显式类型转换。

1.发生隐式转换的情况

混合运算:级别低的类型的值向级别高的类型的值转换;

将表达式的值赋给变量:表达式的值向变量类型的值转换;

实参向形参传值:实参的值向形参的值进行转换;

函数返回结果:返回的值向函数返回类型的值进行转换。

2.显式类型转换

方式为

(1)强制法

(类型名)表达式

或者

(类型名)(表达式)

(2)函数法

类型名 (表达式)

它们都将表达式强制地转换为类型名所代表的类型的值。