• C语言的本质(5)——类型转换的本质与处理


    数据类型转换的方式

    C 语言中的数据类型转换可分为隐式转换和显式转换两种。

    隐式转换

    隐式转换也可称作为自动转换,它经常以以下几种形式发生:

    1、在计算一个同时出现多种数据类型的表达式时,将所有数据类型都转换为同一种数据类型。

    2、在对数据进行输出时,按指定格式将数据输出。

    3、利用赋值运算符将数据转换为运算符左边指定的数据类型。

    4、在对函数调用时,如果形参与实参的数据类型不一致,实参会自动转换为形参的数据类型。

    根据转换发生的形式,可将隐式转换分为类型:一般算术转换、输出转换、赋值转换与函数调用转换。

    一般算术转换

    这种转换类型会经常出现,它是通过编译器自动实现的,不同类型的数据在一个表达式中会自动转换为最长的类型,例如:

    有如下定义char a; int b,e; float c; double d;

    计算a*b+c-d/e 时,按计算顺序说明类型转换:

    1、 a*b; // char 类型的a 转换为int 类型的值, 再和int 类型的b 相乘。

    2、d/e; // int 类型的e 转换为double 类型的值,然后double类型的d 再和e 相除。

    3、a*b+c; // int 类型的a*b 转换为float 类型值,再和float 类型的c 相加。

    4、a*b+c-d/e; // float 类型的(a*b+c)转换为double 类型的值,再和double类型的d/e 相减。

    不考虑过程,最终表达式的值为最长类型(这里是double)的值。

    格式输出转换

    这种转换类型是将某种类型的数据按照输出格式转换成指定格式。例如:

    main(){int a=65;printf("%c ",a);} //输出“A”

    此程序是将ASCII 值为65 的字符输出来,所以输出结果是“A”。

     

    赋值转换

    在这种转换中,会出现赋值运算符“=”,就是要将运算符右边的数据类型转换为运算符左边的数据类型,例如:

    int main()
    {
    	inta=3.15;
    	printf("%d
    ",a);
    } //输出结果是3


    之所以会出现这种结果,就是因为运算符右边的3.15 是浮点型常量,它要被转换为运算符左边的整型数据,导致整型变量被赋

    值为3。

     

    函数调用转换

    此种类型的转换主要会出现在函数调用时形参跟实参数据类型发生不一致的场合,例如:

    int mul(int x,int y) //函数中的形参为int
    {
    	int a;a=x*y;
    	return(a);
    }
    int main()
    {
    	float a=1.23,b=2.35;
    	int c;c=mul(a,b); //调用函数时,由于实参是float,所以实参首先会转换为int,再执行函数体部分
    	printf("%d",c);
    } //输出结果是2


    显式转换

    显式转换可分为两种,即强制性数据类型转换以及利用标准函数转换。

    强制性数据类型转换

    强制性数据类型转换是将某一种数据类型强制转换为另外一种数据类型。这一种较常见。强制性数据类型转换的一般格式为:

    (类型标识符)表达式


    例如:

    int main()
    {
    	float a=5.6,b=2.3;
    	printf("%d
    ",(int)a%(int)b);
    }


    由于运算符“%”要求两个数据必须为int 类型,如果不进行强制性数据类型转换,则系统会提示出错信息,所以浮点型数据a 和

    b 先各自转换为整型数据5 和6,再进行求余运算,输出结果是1。

    标准函数转换

    这种转换是利用C 语言中的标准函数将某一种数据类型转换为另外一种数据类型。例如:

    int main(void)
    {
    int a; float b ; char*c="123.45xy", *d;
    b=atof(c); //将字符串c 转换为float 型数据
    a=atoi(c); //将字符串c 转换为int 型数据
    itoa(a,d,10); //将十进制数a 转换为字符串数据并且存放在字符型指针d 所指向的字符串
    printf("%.4f,%d,%s
    ",b,a,d); //将浮点型数据b、整型数据a 以及字符串数据d 分别按照浮点型、十进制数整型和字符串格式
    输出,输出结果是:123.4500,123,123
    }


    常见问题

    在对数据类型进行转换时,是为了程序的需要,可有的时候却会带来意想不到的安全隐患和错误,这就是非安全转换、输入输

    出格式错误与运算符数据不匹配。

    1、非安全转换

    非安全转换是将一种数据类型长的转换成其它数据类型短的数据,使其值的表示范围被缩小所出现的错误。它有如下几种情

    况:

    较大整数转换为较短的类型

    C 语言系统一般不检测这种类型的错误,大部分的编译器在可能出现非安全转换是不会给出警告信息,因此在编程时需避免此

    类型转换。

    int main()
    {
    	long i=123456;
    	printf("%d
    ",i);
    } //其输出结果为-6716.


    又如

    int main(){
    	unsigned i=65535; 
    	int j ; 
    	j=i; 
    	printf("%d
    ",j)
    }//输出结果为-1.

    有符号负数转换为无符号数

    例如:

    int main()
    {
    int i=-1;
    printf("%u",i);
    } //其结果为65535


    当由有符号数转换为无符号数时,原来的符号位将不作为符号,而作为数据的一部分。

    双精度类型转换为单精度类型

    例如:

    int main()
    {
    double i=10.123456789;
    float j=i;
    printf("%.9f
    ",j);
    } //输出为10.123456955

     

    int main()
    {
    double i=12345678912345.123;
    float j=i;
    printf("%f
    ",j);
    } //输出为12345679020032.000000


    由于双精度类型转换成单精度类型时,可能出现以下两种情况:其一,降低精度,截断尾数,保留前8 位有效数字,后面的数字

    无意义,如例1;其二,若数值超出了单精度所表示的范围,则得到的数据无意义,且系统不提示错误,因此在遇到较大的数据,或对

    数据精度要求比较高时,应避免进行此类的转换。

    浮点数转换为整型

    当浮点数转换成整型数据时,舍弃小数,不进行四舍五入,例如:

    int main()
    {
    double i=15.99999;
    int j=i;
    printf("%d
    ",j);
    } //其输出为15


    因此,若需要计算结果尽可能高的精度,应避免此种类型的转换。

    2、输入输出格式错误

    这种错误会出现在格式输入与格式输出函数中。例如:

    int main()
    {
    	int i=2; 
    	printf("%f",i);
    } //会出现编译错误(数据类型不一致)


    3、算术运算“/”、“%”与数据类型不匹配

    例如:

    int main( )
    {
    int i=7,j=2;
    printf("%d
    ",i/j);
    } //输出结果为3


    程序的本来目的是想得到结果3.5,可是结果却是3,,是因为变量i 和j 都是int 类型的,其结果也是int 类型的,如果

    想得到3.5 的话,就要将i 和j 都要强制转换为float 类型;

    int main( )
    {
    float i=12.45,j=6.3;
    printf("%d
    ",i%j);
    } //提示错误: 非法地使用浮点数在main函数中


    之所以会出现系统提示错误,是因为运算符“%”左右两侧的数

    据类型都必须是int,但程序中两个变量却都不是int 类型的,因此,想让系统不出错误,就必须将两个变量都强制转换为float 类型。

    从上述两个例子来看,对于算术运算符“/”和“%”,一定要注意数据类型的匹配。

     

    在C 语言中,多种数据类型之间的转换有它出现的必然性,也就是在某些情况下,数据转换是必须的,但应尽量避免出现将数

    据长的类型转换为数据短的类型、输入输出格式上的错误以及运算符数据类型不匹配等问题。

  • 相关阅读:
    深度学习笔记(21)- 深度看图
    Mysql数据库主键,外键,索引概述
    软件架构的演进:单体、垂直、SOA、微服务
    2018年阿里巴巴关于Java重要开源项目汇总
    全面了解HTTP和HTTPS
    创业互联网公司如何搭建自己的技术架构
    Dubbo与Spring Cloud的比较
    Java工程师技能点梳理
    使用SpringCloud将单体迁移至微服务
    Springmvc与Struts区别?
  • 原文地址:https://www.cnblogs.com/new0801/p/6177120.html
Copyright © 2020-2023  润新知