数据转换:
在表达式中,所有的数据都会向宽型转换,有两个原则:
1、为防止精度损失,如果必要的话,类型总是被提升为较宽的类型;
2、所有含有小于整型的有序类型的算术表达式在计算之前其类型都会被转换成整型。
值得注意的是有关符号和无符号数之间的转换。
显式转换较为简单,我们关心更多的是隐式转换。看看下面的程序输出为多少:
signed int a;
unsigned int b;
a= -1;
b= 0;
cout<< a + b <<endl;
cout<< (signed int)(a+ b) <<endl;
cout<< (unsigned int(a))+ 3 << endl;
cout<< unsigned int(a)<< endl;
我们先看看结果:
4294967295
-1
2
4294967295
说明:
上面的例子很好的说明了符号数与无符号数之间的隐式转换的规则——符号数向无符号书转换!
在上面的例子中,a是符号整型(signed int),a=-1,b是无符号整型(unsignedint),b=0,那么理论上a+b=-1+0=-1,而答案的显示为4294967295。这个数是个什么意思?但是我们将这个很大数强制转换为signed int时,即(signed int)(a+b),得到的结果为-1。现在我们来分析一下上面的现象:
首先要知道一点无符号数和符号数在计算机中的表示方式。假如存在一个4位数据cc,那么对于无符号的数据即unsigned cc,它的取值范围为:0x0---0xf。而对于符号数,他的最高位是不代表数据,而是代表符号(1为负,0为正)。符号数的取值范围用下图可以很好的解释:
从上图可以发现,对于4位有符号数,他的正整数范围为0-7即,0000-0111,它的负数范围为-1---8即,1111-1000,可以发现,整最大是7,而负最大是-8!那是因为0的存在,0占用了一个正数范围!而且还得注意的是0的下一位是-1,在有符号的二进制中,-1为全1,即1111。记住这个图!!。
那么对于上面的例子的解释就不难理解了。由于符号数与无符号数之间的隐式转换的规则是符号数向无符号书转换。那么对于a+b,a为-1,对于32为系统,为0xffffffff,0xffffffff将自动隐式转换为无符号数,对于无符号数的0xffffffff=232-1=4294967295,因此,a+b不得-1,而是得4294967295。
那么也不难理解(signedint)(a+b)=-1的原理了,因为-1的二进制就是为0xffffffff。
关于数据转换另一个难点是指针转换。
看看下面的代码:
unsignedint a = 0xfffffff7;
unsignedchar i = (unsigned char)a;
char* b = (char *)&a;
printf("%08x,%08x",i,*b);
下面的代码的输出为:
0x000000f7
0xfffffff7
对于第一个产生截断很好理解,char为8为,只能存储int a的低8位,第二个就有点奇怪了。b为一个指向char的指针,那么在我看来,b指向的是一个字节的存储单元,但是最后却输出了0xfffffff7,那么对于c的printf函数,虽然b是一个char指针,但是指向一个了一个int,那么最后在printf中输出*b,就会输出整个int,而不是这个int的低位1字节。
关于指针的转换又有个奇怪的现象,看下面的代码:
int *a = new int;
*a= 300;
char *b;
b= (char*)(a);
cout<< *a << endl;
cout<< *b << endl;
最后的输出为:
300
,
第一个输出为300毋庸置疑,但是第二个也比较有趣,输出一个逗号“,”,仔细分析,300的二进制为:0001 0010 1100,那么对于char *b指向的是一个单字节存储单元,也就是说b是指向了0001 0010 1100的第八位即0010 1100,该数对应的asic码为逗号“,”,也就是说,cout与printf是不同的!!!Cout出现了截断!!