6.4 数据类型转换

HarmonyOS

  6.4 数据类型转换

  上一讲介绍了不同类型数据的输入和输出方法,特别强调了字符型数据输入和输出要注意的问题。本节主要讲C语言表达式的数据类型以及如何进行数据类型转换。

  在学习表达式数据类型及转换之前,我们来回顾一个前面学过的程序。

  例1:从键盘上输入正整数n,求sum=1+ 1/2 + 1/3 + .... + 1/n。程序如下:

  #include <stdio.h>int main( ){int i,n;double sum=0;scanf("%d",&n);for(i=1;i<=n;i++) sum=sum+1/i;printf("%f",sum);return 0;}当输入10回车后,我们发现显示结果是1.000000,与我们预期不一样,问题出在什么地方呢?原来当i>1时,1/i的结果都是0,导致了sum只得到了第一项,即1的值。为什么当i>2时,1/i的结果是0而不是一个小数,这就是本节要讲的主要问题。

  C语言允许不同的数据类型在算术表达式中混合使用,表达式计算结果的数据类型由一定规则指定。上例中1和i都是整型,因为两个整数的算术运算结果也是整型,因此表达式1/i运算结果是整数,相当于取整数运算,小数被直接舍掉了。注意是直接舍掉,不是四舍五入。

  整型与整型运算的表达式数据类型是整型,实型与实型的运算表达式数据类型也是实型、实型与整型运算表达式的结果是实型。那么当字符型、短整型、长整型、长长整型、单精度实型、双精度实型和长双精度实型等混在一起的运算表达式的数据类型是什么呢?可以通过一张表查看。

表达式类型转换表

  从表中可以看出,浮点数的优先级高于字符型、整型,即浮点数与字符、整数一起运算时,表达式结果是浮点数,计算机会把字符型或整型数据转换等数值的浮点数后再与浮点数一起运算。字符型和整型运算的表达式类型为整型。同类型的有符号整数与无符号整型运算表达式是无符号整型。在两个整数运算中,表达式的类型的优行级是long long > long > int > short;在两个浮点数的运算中,表达式的类型优先级是long double > double > float。有一个简单的记忆办法:整型或实型数据混合运算时,数据类型存储占用字节较多的运算量类型优先级越高。 看例2及输出结果。

  例2:整型与实型的运算

  #include <stdio.h>int main( ){int a=10;long long b=100;printf("%d\n",a+20.0);printf("%.1f\n",a+20.0);printf("%ld\n",b+20.0);printf("%.1f\n",b+20.0);printf("%.1f\n",b+20.0f);return 0;}第一行printf语句是试图按整型格式(%d)输出整型变量a与双精度实型常量20.0之和,结果显示0,说明表达式运算结果不是整型。

  第二行是按浮点数(%.1f)格式输出a+20.0这个表达式,结果显示30.0,说明了该表达式是双精度实型数。

  第三行是试图按长长整型格式(%Ld)显示long long型变量b与双精度浮点数常量20.0相加的表达式,结果显示为0,说明表达式的值不是long long型的。

  第四行按浮点数格式(%f)输出b+20.0表达式,结果显示120.0,说明该表达式确实是一个双精度实浮点数。

  第五行按浮点数格式(%f)输出long long 变量b与单精度浮点数20.0表达式,结果显示120.0,说明long long与float运算的结果是float数据类型

  上述例子说明,计算机会自动把类型优先级较低的数转换成类型较高的数后再完成最后计算。再来看一个表达式的类型,如:

  'A'+12-10.05表达式是字符型、整型和双精度实型的混合计算,根据上述原则,该表达式应该是双精度实型。计算过程是字符'A'先转换成整数再与12计算,结果是整型77,再把整型77自动转换双精度浮点数后再减去10.05,结果是66.95。

  但是把某类型的表达式赋给不同类型的变量会发生什么呢?如把一个整型数赋给浮点数或把一个浮点数赋给整数,如;

  int a;double b;a=3.67;b=20;上述代码段,a变成了3,b变成了20.0。可见浮点数赋给整数仅是把浮点数的整数部分(不是四舍五入)变成整数后赋给整型变量。整数赋给实型变量是先把整数变成等值浮点数再进行赋值。要注意的是,以上都不是直接把浮点数的二进制赋给整型变量。

  当把单精度浮点数赋给双精度浮点数时,精度不会损失。但当把双精度浮点数赋给精度实型变量时,精度会有损失,如:

  float a=123456789.0;printf("a=%.2f\n",a);的显示结果为123456792.00。可见精度只保留到了第7位,第8位起不再是精确数据了。

  事实上在浮点数类型中,占用字节少的数据赋值给占用字节多的变量数据不会有损失。占用字节数多的类型赋值给占用字节少的变量才会引起数值或精度的变化。对于字符型数据和整型数也是一样。如:

  short a;int b;long c;long long d;a=b=c=d='a';printf("%d,%d,%d,%d\n",a,b,c,d);以上代码把一个字符分别赋给了不同类型的四个变量,结果显示都是一样的,即'a'的ASCII值97。反过来就不然了。现在,我们反过来看一下,把字节多的数据赋给占用存储空间小的变量。如:

  char a;short b;int c=0x12345678;a=c;b=c;printf("%x,%x\n",a,b);结果显示:78,5678。我们可以看出什么吗?当c赋给a时,由于c占用4个字节,因此只完成了把c的最低一个字节,即内存地址xx01对应内存空间中的值0x78赋给了a;当c赋给b时,因为b只有两个字节,因此,只把c的最低两个字节(内存地址xx01、xx02),即0x5678赋给了b。示意图如下:

a、b、c的内存映像

  本例为了更好地说明,我们采用了十六进制表示整数。前面已经学习,一个十六进制位对应4个比特,因此一个字节对应两个十六进制位。对于0x12345678这个整数,可以看到是按从右至左的顺序分别从低地址到高地址依次保存的。所以当字节数较多的整数赋给字节数较少的整型变量时,只从整数中的低字节取对应整型变量长度的内存数据赋值即可。

  当i是整型变量,如果想把表达1/i转换成实型,前面我们学习了一种最简单的方法,即把1变成浮点数1.0即可以实现,此时1.0/i变成了双精度浮点数与整型变量的运算,结果是双精度浮点数。

  现在给出另一种类型转换方法,称为强制类型转换。方法为:

  (数据类型名)表达式

  括号不能省略,数据类型名可以是我们学习到的类型。

  要注意的是,这是一个转换表达式,并不能把表达式本身转换成对应的类型。如:上面1/i的例子可以改写为:

  (double)1/i 或 1/(double)i;其中“(double)i”本身是一个表达式,其类型是double型的,但i仍是是整型的,且数值不会被改变。

  来看一下几个转换表达式的结果:

  (double)3 双精度浮点数3.000000(int)3.8 整数3(double)(5/2) 双精度浮点数2.000000(double)5/2 又精度浮点数2.500000注意第三行的值并不是2.500000,而是5整除以2后再变成又精度数,所以结果为2.000000。如果想把数值较大的整型数据转化成占字节数较少的数据类型呢?如:

  int c=0x12345678;printf("%x,%x\n",(char)c,(short)c);代码执行结果显示:78,5678。说明转换时都是保留整数的低字节部分。

  本节详细介绍了C语言表达式的数据类型及数据类型转换,表达式赋给不同数据类型时的自动转换原则,以及强制类型转的方法。探讨了类型转换时精度损失问题。本节就讲到这里,下一讲再见。

标签: HarmonyOS