4.3 数据类型的转换

C语言中的数据类型转换就是将数据(变量、数值、表达式的结果等)从一种类型转换为另一种类型。转换的方式有自动转换和强制转换两种。

4.3.1 自动类型转换

自动类型转换就是编译器默默地、隐式地、偷偷地进行的数据类型转换,这种转换不需要程序员干预,会自动发生。

将一种类型的数据赋值给另外一种类型的变量时就会发生自动类型转换。

例如:

    float f=200;

200是int类型的数据,需要先转换为float类型才能赋值给变量f。

再如:

    int a=f;

f是float类型的数据,需要先转换为int类型才能赋值给变量a。

提示

赋值号两边的数据类型不同时,需要把右边表达式的类型转换为左边变量的类型,这可能会导致数据失真,或者精度降低;所以,自动类型转换并不一定是安全的。对于不安全的类型转换,编译器一般会给出警告。

自动类型转换遵循以下几种规则:

(1)运算时,若参与的数据类型不同,首先将它们转换为同一类型。

(2)浮点型数据的运算都必须转换为double型。

(3)运算过程中出现short型和char型时,将它们转换为int型。

(4)对数据转换应向长度增加的方向转换,确保计算后精度不会丢失。例如,参与运算的为int型和long型,那么将int型转换为long型。

(5)赋值时,若赋值号右边的表达式数据类型长度比左边长,则在赋值时将右边表达式的类型转换为左边变量类型时会丢失一部分数据,造成精度降低。

自动类型的转换规则,如图4-16所示。

图4-16 自动类型转换

【例4-5】编写程序,定义float型变量x,初始化x为6.28395,定义int型变量s1,r,初始化r为5,定义double型变量s2,然后求出变量r与x的乘积,将计算结果赋给变量s1与s2,分别输出s1和s2。(源代码\ch04\4-5)

    #include<stdio.h>
    int main()
    {
    float x = 6.28359;
    int s1, r = 5;
    double s2;
    s1 = r * x;
    s2 = r * x;
    printf("s1=%d, s2=%f\n", s1, s2);
    return 0;
    }

运行上述程序,结果如图4-17所示。

图4-17 隐式转换

【代码解析】

本例用于演示在运算过程中,编译器对不同类型的变量进行隐式转换的过程。在代码中,首先定义三种不同类型的变量,分别是float型的x,int型的s1与r,double型的s2。通过对“s1 = r*x;”表达式进行计算时,编译器会将它们都转换为float型进行计算,所以表达式计算的结果也为float型,但是进行赋值操作时,左边变量s1为int型,那么赋值时便将小数部分全部舍弃,保留整数赋值给s1;而作为对比,s2本身为double型,其精度比float高,所以不用舍弃小数部分的位数,可以直接进行赋值操作,会输出不同结果s1与s2。

提示

浮点型数据float在转换为int型的时候是直接舍弃掉小数部分的,而不是四舍五入。

4.3.2 强制类型转换

强制类型转换就是程序员明确提出的、需要通过特定格式的代码来指明的一种类型转换。换句话说,自动类型转换不需要程序员干预,强制类型转换必须有程序员干预。

强制类型转换的格式为:

    (类型名称) 变量名或者表达式;

其中的类型名称为要转换到的数据类型。

例如:

    (double) z;   // 将z转换为double型
    (int) (x+y);   // 将表达式x+y的结果转换为int型
    (float) 5;     // 将常量5转换为float型

【例4-6】编写代码,定义int型变量x=160,y=9,定义double型变量z,将x当作总数,y当作数目,求平均值z,根据这个算术关系,在计算过程中使用强制类型转换,将x转换为double型,最后输出z的值。(源代码\ch04\4-6)

    #include <stdio.h>
    int main()
    {
    int x = 160;  // 总数
    int y = 9;    // 数目
    double z;     // 平均数
    z = (double) x / y;
    printf("平均数= %lf!\n", z);
    return 0;
    }

运行上述程序,结果如图4-18所示。

图4-18 强制类型转换

【代码解析】

本例用于演示如何在运算过程中对变量进行强制类型转换。首先定义int型变量x与y,double型变量z,在计算z=x/y的过程中,如果不进行干预,那么最终的运算结果也是int类型,小数部分将被丢弃;虽然是z是double类型,可以接收小数部分,但是心有余力不足,最后只能接收到整数部分,这就导致除法运算的结果严重失真。如果写为“z=(double) x/y”,那么运算的结果将会更为精确。

注意:

(1)对于除法运算,如果除数和被除数都是整数,那么运算结果也是整数,小数部分将被直接丢弃;如果除数和被除数其中有一个是小数,那么运算结果也是小数。

(2)“( )”的优先级高于“/”,对于表达式(double) x/y,会先执行(double) x,将x转换为double类型,然后再进行除法运算,这样运算结果也是double类型,能够保留小数部分。注意不要写作(double) (x/y),这样写运算结果将是17.000000,仍然不能保留小数部分。