一、自动类型转换

    一般来说,同一句语句或表达式应该使用同一种类型的变量和常量。如果使用了多种类型的变量和常量(类型混用),C 会自动把它们转换成同一种类型。自动类型转换为我们写程序提供了方便,却也带来了危机。因粗心大意而造成的类型混用也许会导致程序运行出错。以下是自动类型转换的基本规则:

    1. 在表达式中,char 和 short 类型的值,无论有符号还是无符号,都会自动转换成 int 或者 unsigned int(如果 short 的大小和 int 一样,unsigned short 可表示的最大值就大于 int,在这种情况下,unsigned short 被转换成 unsigned int)。因为它们被转换成表示范围更大的类型,故而我们把这种转换称之为“升级promotion)”。

    2. 按照从高到低的顺序给各种数据类型分等级,依次为:long double, double, float, unsigned long long, long long, unsigned long, long, unsigned int 和 int。这里有一个小小的例外,如果 long 和 int 大小相同,则 unsigned int 的等级应位于 long 之上。char 和 short 并没有出现于这个等级列表,是因为它们参与运算时就应该已经被升级成了 int 或者 unsigned int。

    3. 在任何涉及两种数据类型的操作中,它们之间等级较低的类型会被转换成等级较高的类型。

    4. 在赋值语句中,= 右边的值在赋予 = 左边的变量之前,首先要将右边的值的数据类型转换成左边变量的类型。也就是说,左边变量是什么数据类型,右边的值就要转换成什么数据类型的值。这个过程可能导致右边的值的类型升级,也可能导致其类型降级demotion)。所谓“降级”,是指等级较高的类型被转换成等级较低的类型。

    5. 作为参数传递给函数时,char 和 short 会被转换成 int,float 会被转换成 double。使用函数原型可以避免这种自动升级。这点我以后会详细讲解。

    类型升级通常不会有什么问题,但是类型降级却会带来不少问题。例如:

        char ch = 1222;

1222 降级为 char,但 char 无法表示 1222。再如:

        int j = 22.2;

22.2 降级为 int,小数部分被截断。


二、类型转换运算符

    使用类型转换运算符可以指定我们想要进行的类型转换。类型转换运算符由括号和类型名组成:

        (type)

其中,我们应该用我们想转换成的类型替换掉 type,例如:(long), (unsigned long)。

    类型转换运算符应该放在值的前面:

        int i = (int)1.1 + (int)2.2;

1.1 在加法运算前就因为类型转换运算符而降级为 int,其值变为 1。类似地,2.2 也降级为 int,其值变为 2。又如:

        int j = 20;
        double k = (double)j;

j 的值被转换成 double,然后用于初始化 k。


三、小例子

    #include <stdio.h>

    int main(void)
    {
        char ch;
        int i;
        float fl;
        double db;

        db = fl = i = ch = 'C';                 /* 10 */
        printf("ch=%c, i=%d, fl=%2.2f, db=%2.2f\n", ch, i, fl, db);

        ch = ch + 1;                            /* 13 */
        i = db + fl + 2 * ch;                   /* 14 */
        fl = 2.0 * ch + i;                      /* 15 */
        db = 22 * i + ch - fl;                  /* 16 */
        printf("ch=%c, i=%d, fl=%2.2f, db=%2.2f\n", ch, i, fl, db);

        i = 666.6 + 777.7;                      /* 19 */
        printf("Now i = %d\n", i);
        i = (int)666.6 + (int)777.7;            /* 21 */
        printf("Now i = %d\n", i);

        return 0;
    }

我的系统中,char 是 8 位的,int 是 32 位的。输出为:

    ch=C, i=67, fl=67.00, db=67.00
    ch=D, i=270, fl=406.00, db=5602.00
    Now i = 1444
    Now i = 1443

第 10 行,'C' 的值被转换为 char,然后赋值给 ch。ch 的值被转换成 int,然后赋值给 i。以此类推。

第 13 行,= 右边的 ch 的值先被转换成 int,然后和 1 相加,得到 32 位的 int 类型整数 68。最后,68 降级为 char,然后赋值给 ch。在 ASCII 中,D 的编码是 68。

第 14 行,ch 的值被转换成 int,然后和 2 相乘得 136。fl 的值被转换成 double,然后和 db 相加,其和再与转换成 double 的 136 相加得 270.0 。最后,270.0 被转换成 int,然后赋值给 i。

第 15 行,ch 的值被转换成 double,然后和 2.0 相乘,i 的值被转换成 double,然后和前面得到的乘积相加,相加的得数被转换成 float,然后赋值给 fl。

第 16 行,22 和 i 相乘得 5940,ch 的值被转换成 int,然后和 5940 相加得 6008,然后,6008 被转换成 float,再和 fl 相减得 5602.0f,最后 5602.0f 被转换成 double,再赋值给 db。

第 19 行,666.6 和 777.7 相加得 1444.3,然后 1444.3 被降级成 int,再赋值给 i。

第 21 行,类型转换运算符把 666.6 和 777.7 转换为 int,得 666 和 777,它们相加得 1443,最后,1443 被赋值给 i。

注意,类型转换改变的是值的类型,而不是对象的类型,对象的类型自始至终都是不变的。例如:

    i = fl + ch;

ch 的值被转换成 float,而 ch 本身仍然是 char 类型的变量。

参考资料:C Primer 5th Edition
          The C Programming Language 2nd Edition
          C99 标准