自动类型转换

通常,在语句和表达式中应使用类型相同的变量和常量。但是,如果使用混合类型,C 不会像 Pascal 那样停在那里死掉,而是采用一套规则进行自动类型转换。虽然这很便利,但是有一定的危险性,尤其是在无意间混合使用类型的情况下(许多 UNIX 系统都使用 lint 程序检查类型“冲突”。如果选择更高错误级别,许多非 UNIX C编译器也可能报告类型问题)。最好先了解一些基本的类型转换规则

  1. 当类型转换出现在表达式时,无论是 unsigned 还是 signed 的 char 和 short 都会被自动转换成 int,如有必要会被转换成 unsigned int。在 K&R 时的 C 中,float 会被自动转换成 double(目前的 C 不是这样)。由于都是从较小类型转换为较大类型,所以这些转换被称为升级(promotion)。
    PS:char、short 转换为 unsigned int 的情况 —— 如果short与int的大小相同,unsigned short就比int大。
    这种情况下,unsigned short会被转换成 unsigned int。
  2. 涉及两种类型的运算,两个值会被分别转换成两种类型的更高级别。


  1. 类型的级别从高至低依次是 long double、double、float、unsigned long long、long long、unsigned long、long、unsigned int、int。例外的情况是,当 long 和 int 的大小相同时,unsigned int 比 long 的级别高。之所以 short 和 char 类型没有列出,是因为它们已经被升级到 int 或 unsigned int。


  1. 在赋值表达式语句中,计算的最终结果会被转换成被赋值变量的类型。这个过程可能导致类型升级或降级(demotion)。所谓降级,是指把一种类型转换成更低级别的类型。


  1. 当作为函数参数传递时,char 和 short 被转换成 int,float 被转换成 double。之后将介绍,函数原型会覆盖自动升级。


类型升级通常都不会有什么问题,但是类型降级会导致真正的麻烦。原因很简单:较低类型可能放不下整个数字。例如,一个 8 位的 char 类型变量储存整数 101 没问题,但是存不下 22334。

如果待转换的值与目标类型不匹配怎么办?这取决于转换涉及的类型。待赋值的值与目标类型不匹配时,规则如下。

  1. 如果目标类型是无符号整型,且待赋的值是整数时,额外的位将被忽略。例如,如果目标类型是 8 位 unsigned char,待赋的值是原始值求模 256。
  2. 如果目标类型是一个有符号整型,且待赋的值是整数,结果因实现而异。
  3. 如果目标类型是一个整型,且待赋的值是浮点数,该行为是未定义的。


如果把一个浮点值转换成整数类型会怎样?当浮点类型被降级为整数类型时,原来的浮点值会被截断。例如,23.12 和 23.99 都会被截断为 23,-23.5 会被截断为 -23。

强制类型转换


通常,应该避免自动类型转换,尤其是类型降级。但是如果能小心使用,类型转换也很方便。我们前面讨论的类型转换都是自动完成的。然而,有时需要进行精确的类型转换,或者在程序中表明类型转换的意图。这种情
况下要用到强制类型转换(cast),即在某个量的前面放置用圆括号括起来的类型名,该类型名即是希望转换成的目标类型。圆括号和它括起来的类型名构成了强制类型转换运算符(cast operator),其通用形式是:(type),用实际类型替换 type 即可。

int mice;
mice = 1.6 + 1.7;
mice = (int)1.6 + (int)1.7;

第 2 行使用自动类型转换。首先 1.6 + 1.7 得 3.3,然后为了匹配 int 类型变量,3.3 被类型转换截断为 3。
第 3 行使用强制类型转换。首先 1.6 和 1.7 被转换为 1,然后将值相加的结果 2 赋值给 mice。

本质上,两种类型转换都好不到哪里去,要考虑程序的具体情况再做取舍。

一般而言,不应该混合使用类型(因此有些语言直接不允许这样做),但是偶尔这样做也是有用的。C语言的原则是避免给程序员设置障碍,但是程序员必须承担使用的风险和责任。