本节必须掌握的知识点:
整型提升
浮点型和整型转换
浮点型转换
普通算术类型转换
示例十二
在实际项目应用过程中,我们通常会根据实际需要,对数据进行扩展和截取,我们称之为数据类型转换。对数据类型的转换需要遵循以下规则。
3.7.1 整型提升
在可以使用int型或unsigned int型的表达式中,也可以使用有符号或无符号类型的char、short int、int类型,还可以使用枚举对象。可根据实际需要确定数据类型。
无论哪种情况,如果int型可以表示出原数据类型的所有值,就将值转换为int型,否则转换为unsigned int型。VS编译器默认缺省的数据类型为int类型。
整型提升不会改变符号和数值。char型是否作为有符号类型来处理,由编译器而定。VS编译器中char型作为有符号整型处理,取值范围-128~127。
■有符号整型和无符号整型
整数类数据类型之间互相转换时,若原数值能用转换后的数据类型表示,则数值不会发生变化。
举例
//有符号整型提升
short int a = 123;
int b = (int)a;//b = 123,short int类型转换为int类型,(int)可省略
printf("a = %d,b = %d\n", a, b);
输出结果:a = 123,b = 123 原值没有发生变换
有符号整数转换为位数相同或位数更多的无符号整数时,如果该有符号整数不为负数,则数值不会发生变化。
否则,若无符号整数的位数较大,则先将有符号整数提升为与无符号整数长度相同的有符号整数。然后再与无符号整数类型可表示的最大数加1后的值相加,将有符号整数转换为无符号整数。
举例
//有符号整型提升为无符号整型:正整数
unsigned int c = (unsigned)b; //(unsigned)可省略
printf("b = %d,c = %u\n", b, c);
//有符号整型提升为无符号整型:负整数
short int d = -1;
unsigned int e = (unsigned)d; //e=4294967295,强制类型转换(unsigned)可省略
printf("d = %d,e = %u\n", d, e);
输出结果:
b = 123,c = 123 //有符号整型提升为无符号整型:正整数不变
d = -1,e = 4294967295 //有符号整型提升为无符号整型:负整数变为4294967295
有符号数转换过程:
第一步:先将16位short有符号类型变量d提升为32位有符号类型-1(16进制数0ffffh提升为0ffffffffh)。
32位有符号类型0ffffffffh+1+32位无符号整型最大值0ffffffffh,等于0ffffffffh(十进制数4294967295)。
将整数类数据类型转换为位数更少的无符号整数时,除以比位数较少的数据类型可表示的最大符号数大1的数,所得的非负余数就是转换后的值。
将整数类数据类型转换为位数更少的有符号整数时,以及将无符号整数转换为位数相同的有符号整数时,如果不能正确表示转换后的值,则此时的操作由编译器而定。
举例
//有符号int整型转为无符号unsigned short类型
int f = -1;
unsigned short g = (unsigned short)f;//g=65535,0xffffffff截取为0ffffh
printf("f = %d,g = %d\n", f, g);
//有符号int整型转为无符号short类型
short h = (short)f;// 0xffffffff截取为0ffffh
printf("f = %d,h = %d\n", f, h);//h=-1
//无符号unsigned int整型转为有符号short、int类型
unsigned int i = 4294967295;//十六进制数0xffffffff
short j = (short)i; // 0xffffffff截取为0ffffh
int k = (int)i; // 0xffffffff保持不变
printf("i = %u,j = %d,k = %d\n", i, j,k);//j=-1,k=-1
输出结果:
f = -1,g = 65535
f = -1,h = -1
i = 4294967295,j = -1,k = -1
其实没有那么复杂,只需要将整数转换为十六进制数,然后截取缩短后的位数即可。
3.7.2 浮点型和整型转换
将浮点型的值转换为整数类数据类型时,会截断小数部分。整数部分的值不能用整数类数据类型表示时的操作未定义。
将整数类数据类型的值转换为浮点型时,如果数据类型转换后的结果在数值范围内不能正确表示,那么会根据编译器定义的方法取大于或小于原值的最接近的近似值作为转换结果。
举例
//整型转换为浮点型
int x = 123;
double y = (double)x;//y=123.000000,强制类型转换(double)可省略
printf("x = %d,y = %f\n", x, y);
//浮点类型转换为整型
double n = 123.123;
int m = (int)n;
printf("n = %f,m = %d\n", n, m);
输出结果:
x = 123,y = 123.000000
n = 123.123000,m = 123
浮点型转整型,截取整数部分。整型转浮点型,填充小数部分为0。
3.7.3 浮点型转换
float型提升为double型或long double型时,以及double 型提升为 long double型时,值不会发生变化。
double型转换为float型时,以及long double型转换为float型时,会根据编译器定义的方法取大于或小于原值的最接近的近似值作为转换结果。
举例
//浮点型相互转换
float w = (float)123.123456; //默认浮点常量值为double类型
double z = (double)w;
double p = 123.123456789;
float l = (float)p;
printf("w = %f,z = %f,p = %f,l = %f\n", w, z, p,l);
输出结果:
w = 123.123459,z = 123.123459,p = 123.123457,l = 123.123459
浮点类型转换后的值为近似值。长浮点型转短浮点型需要截掉后面的小数值。短浮点型转长浮点型尾数部分填充0。
3.7.4 普通算术类型转换
许多具有算术类型操作数的双目运算符都会执行操作数的数据类型转换,并用同样的方法决定转换结果的数据类型。数据类型转换的目的是通用数据类型,该数据类型亦是转换结果的数据类型。这一过程称为普通算术类型转换。
■规则如下:
若有一个操作数为long double型,则将另一个操作数转换为long double型。
若有一个操作数为double型,则将另一个操作数转换为double型。
若有一个操作数为float型,则将另一个操作数转为float型。
若均不符合以上情况,则根据以下规则对两个操作数进行整型提升。
若有一个操作数为unsigned long型,则将另一个操作数提升为unsigned long型。
在一个操作数为long型,另一个操作数为unsigned型的操作数转换为long型。如果long型不能表示unsigned型的值,则将两个操作数转换为unsigned long型。
若有一个操作数为long型,则将另一个操作数转换为long型。
若有一个操作数为unsigned型,则将另一个操作数转换为unsigned型。
否则将两个操作数都转换为int型。
浮点型操作数的值以及浮点型表达式的结果可以超出数据类型所要求的精度和范围进行显示。但是结果的数据类型不会发生变化。
举例
long double a = 1.0;
double b = 2.0;
float c = 3.0;
unsigned d = 4.0;
unsigned long k = 10.0;
long e = 5.0;
int f = 6.0;
unsigned h = 7.0;
short i = 8.0;
unsigned short j = 9.0;
(a + b) //double b 转换为long double类型
(b + c) //float c 转换为double类型
(c + d) // unsigned d 转换为float类型
(c + d) // unsigned d 转换为float类型
(k + d) // unsigned d 转换为unsigned long类型
(e + f) // int f 转换为long类型
(f + h) // int f 转换为unsigned int类型
(f + i) // short i 转换为int类型
(f + j) // unsigned short j 转换为int类型
结论
自动类型转换:
当较短数据类型转换为较长数据类型时,不会丢失精度,可以省略强制类型转换,编译器会自动进行数据类型转换。
自动类型转换规则:
1.若参与运算量的类型不同,则先转换成同一类型,然后进行运算。
2.转换按数据长度增加的方向进行,以保证精度不降低。如int型和long型运算时,先把int量转成long型后再进行运算。
①若两种类型的字节数不同,转换成字节数高的类型。
②若两种类型的字节数相同,且一种有符号,一种无符号,则转换成无符号类型。
3.所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再作运算。
4.char型和short型(在visual c++等环境下)参与运算时,必须先转换成int型。
5.在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型将转换为左边量的类型。如果右边量的数据类型长度比左边长时,将丢失一部分数据,这样会降低精度,丢失的部分直接舍去。
强制类型转换:
当较长数据类型转换为较短数据类型时,会丢失精度,需要使用强制数据类型转换。
3.7.5 示例十二
/*
数据类型转换
*/
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
//有符号整型提升
short int a = 123;
int b = (int)a;//b = 123,short int类型转换为int类型,(int)可省略
printf("a = %d,b = %d\n", a, b);
//有符号整型提升为无符号整型:正整数
unsigned int c = (unsigned)b;//(unsigned)可省略
printf("b = %d,c = %u\n", b, c);
//有符号整型提升为无符号整型:负整数
short int d = -1;
unsigned int e = (unsigned)d;//e=4294967295强制类型转换(unsigned)可省略
printf("d = %d,e = %u\n", d, e);
//有符号int整型转为无符号unsigned short类型
int f = -1;
unsigned short g = (unsigned short)f;//g=65535
printf("f = %d,g = %d\n", f, g);
//有符号int整型转为无符号short类型
short h = (short)f;
printf("f = %d,h = %d\n", f, h);//h=-1
//无符号unsigned int整型转为有符号short、int类型
unsigned int i = 4294967295;//十六进制数0xffffffff
short j = (short)i;
int k = (int)i;
printf("i = %u,j = %d,k = %d\n", i, j,k);//j=-1,k=-1
//整型转换为浮点型
int x = 123;
double y = (double)x;//y=123.000000,强制类型转换(double)可省略
printf("x = %d,y = %f\n", x, y);
//浮点类型转换为整型
double n = 123.123;
int m = (int)n;
printf("n = %f,m = %d\n", n, m);
//浮点型相互转换
float w = (float)123.123456;//默认浮点常量值为double类型
double z = (double)w;
double p = 123.123456789;
float l = (float)p;
printf("w = %f,z = %f,p = %f,l = %f\n", w, z, p,l);
system("pause");
return 0;
}
●输出结果:
a = 123,b = 123
b = 123,c = 123
d = -1,e = 4294967295
f = -1,g = 65535
f = -1,h = -1
i = 4294967295,j = -1,k = -1
x = 123,y = 123.000000
n = 123.123000,m = 123
w = 123.123459,z = 123.123459,p = 123.123457,l = 123.123459
请按任意键继续. . .
代码分析(略)
汇编解析(略)
本文摘自编程达人系列教材《汇编的角度——C语言》。