2.3数据类型的转换
企业里的朋友好像都特喜欢“水桶效应”这个理论,“一只水桶想盛满水,必须每块木板都一样平齐且无破损,如果这只桶的木板中有一块不齐,这只桶就无法盛满水。一只水桶能盛多少水,并不取决于最长的那块木板,而是取决于最短的那块木板”。可是我却有个不同的看法,如果把这个问题换个角度来看一下,比如把每块木板看做一个变量的精度,把盛水的容积看作是变量的和的精度,那么2+3.1415926+’a’的精度会取决于哪块木板呢?
问题描述:
这里给出一句看起来很简单的语句
int a=2+3.1415926
这里面涉及到两个问题,一是两个不同类型的数据相加,是如何进行计算的?二是等号右面的值的数据类型和等号左边的数据类型不同的时候,最后的结果以哪边为准?
实例分析:
int main(void){ int a=2; *定义一个整型变量a */ double b=3.1415926; /*定义一个双精度变量b*/ printf("%d\n",sizeof(a+b)); /*将两个不同类型的变量求和,并查看计算结果的长度*/ return 0; }
|
int a=2; 0041139E mov dword ptr [a],2 /*将一个整型变量看作为dword(32位机中dword表示32bit整数)*/ double b=3.1415926; 004113A5 fld qword ptr [__real@400921fb4d12d84a (415740h)] 004113AB fstp qword ptr [b] /*将一个双精度型变量看作为qword(qword表示64bit整数)*/ printf("%d\n",sizeof(a+b)); 004113AE mov esi,esp 004113B0 push 8 004113B2 push offset string "%d\n" (41573Ch) 004113B7 call dword ptr [__imp__printf (4182B0h)] 004113BD add esp,8 004113C0 cmp esi,esp 004113C2 call @ILT+295(__RTC_CheckEsp) (41112Ch) |
从上面的这个例子可以看出来,在进行加法的时候a+b的时候,不论什么数据类型都会转化为汇编的数据类型,编译器使用的汇编支持的数据类型常见的有以下几种
BYTE |
8位无符号整数 |
WORD |
16位无符号整数 |
DWORD |
32位无符号整数 |
QWORD |
64位整数 |
TBYTE |
80位整数 |
SBYTE |
8位有符号整数 |
SWORD |
16位有符号整数 |
SDWORD |
32位有符号整数 |
其中C语言中整形就先被转换成为了DWORD,而双精度型被转换成为了QWORD,然后这两个变量进行加法运算,这时的运算是浮点加法,而且32位DWORD的a被转换成为了64位QWORD型,所以输出的结果长度为8(单位是字节)。在C语言的层面上来看,整型的a被转换成为了双精度。从这个例子来看的话,可以得到两点:
1 C语言的数据类型都会转换成汇编语言支持的数据类型。
2两种不同精度的数据进行运算,计算的根据是将低精度的数据转换为高精度的数据。
深入剖析:
实际上通常数据类型由短到长排列为char,int,long,float,double。其中长度大的数据类型可以用来表示长度小的数据类型。
double ←float ↑ long ↑ unsigned ↑ int ←char,short |
因此,当运算符两边进行计算的数据类型如果不同的话需要遵循下面的这个图示,基本原则就是低精度要转换为高精度。
这里面有横向和纵向两种箭头,其中横向箭头表示必须要转换,即使是两个float相加,也是必须先要转换为精度更高的double类型来计算,纵向箭头表示在需要的时候转换,如果一个int和一个double相加,int需要转换为double类型,但是两个int类型相加的时候是不需要转换成其他类型的。这些操作都是编译器自动完成的。
第二个问题,例如int x=2+3.1415926
x的定义和2+3.1415926的类型不同,那么最后x的值又会什么呢?原则是以赋值运算符(=)的左边的为准。
这里有两种情形,一种是低精度的值赋值给高精度的变量,另一种是高精度的值赋值给低精度的变量。
这里给出几种常见的转换:
(1) float->int
将float转换为int时,将舍弃float的小数部分,只保留整数部分。
(2) double->int
同float->int
(3) int->float
数值不变,只将变量形式改为浮点形式,在小数点后带若干个0。
(4) int->double
同int->float
(5) float->double
在变量的后面加上零补齐,延长为double型。
(6) double-> float
double型数据转换为float型时,通过截尾数来实现,截断前要进行四舍五入操作。
(7) int->char
在char型变量被赋值为整型变量,保留低地址的8位,其余部分舍弃。
(8) char->int
这个转换涉及到不同编译器的不同处理方式,有的编译环境会将所有的char型都看做是正数,但是有的编译器却会将大于127的数转化为负数。
总结
需要注意的是在把一个高精度的数据转化为一个低精度的数据时,有时会出现部分数值位被抛弃,这是个很明显的问题,一个double需要64位保存,现在把这个64位的数据保存到一个32位的整型变量中,会出很大的偏差。另外尽量避免自动的数据类型转换,这点可以通过强制类型转换来实现。