当在程序的某处我们使用了一种类型而其实对象应该取另一种类型时,程序会自动进行类型转换。
当我们像下面这样把一种算术类型赋给另外一种类型时:
bool b = 42; // b为真
int i = b; // i的值为1
i = 3.14; // i的值为3
double pi = i; // pi的值为3.0
unsigned char c = -1; // 假设char占8比特,c的值为255
signed char c2 = 256; // 假设char占8比特,c的值是未定义的
类型所能表示的值的范围决定了转换的过程:
1、当我们把一个非布尔类型的算术值赋值给布尔类型时,初始值为0则结果为false,否则结果为true。
2、当我们把一个布尔类型的赋给非布尔类型时,初识值为false则结果为0,初始值为true则结果为1.
3、当我们把一个浮点数赋给整数类型时,进行近似处理。结果值将仅保留浮点数中小数点之前的部分。
4、当我们把一个整数赋给浮点类型时,小数部分记为0。如果该整数所占的空间超过了浮点类型的容量,精度可能有损失。
5、当我们赋给无符号类型一个超出它表示的范围的值时,结果是初识值对无符号类型表示数值总数取模后的余数。
6、当我们赋给带符号类型一个超出它表示的值时,结果是未定义的(undefined)。此时程序可能继续工作、可能崩溃、可能生成垃圾数据。
当程序的某处使用了一种算术类型的值而其实所需的是另一种类型的值时,编译器同样会执行上述的类型转换。
例如,如果我们使用了一个非布尔值作为条件,那么它会被自动地转换成布尔值,这一做法和把非布尔值赋值给布尔变量时的操作完全一样;
int i = 42;
if (i)
i = 0; //if条件的值将为true
如果i的值为0,则条件的值为false;i的所有其他取值(非0)都将使条件为true。以此类推,如果我们把一个布尔值用在算术表达式里,则它的值非0即1,所以一般不宜在算术表达式里使用布尔值。
含有无符号类型的表达式
尽管我们不会故意给无符号对象赋一个负值,却可能(特别容易)写出这么做的代码。例如,当一个算术表达式中既有无符号数又有int值时,那么int值就会转换成无符号数。把int值转换成无符号数的过程和把int直接赋给无符号变量一样:
unsigned u = 10;
int i = -42;
std::cout << i + i << std::endl; //输出-84
std::cout << u + i << std::endl; //如果int占32位,输出4294967264
std::cout << i + u << std::endl; //如果int占32位,输出4294967264
在第一个表达式里,两个负整数相加并得到了期望的结果。在第二个表达式里,相加前首先把整数-42转换成无符号数。把负数转换成无符号数类似于直接给无符号数赋一个负值,结果等于这个负数加上无符号数的值。
当从无符号数中减去一个值时,不管这个值是不是无符号值,我们都必须确保结果不能是一个负值;
unsigned u1 = 42, u2 = 10;
std::cout << u1- u2 << std::endl; //正确:输出32
std::cout << u2 - u1 << std::endl; //正确:不过,结果是取模后的值,输出4294967264
无符号数不会小于0这一事实同样关系到循环的写法。
//错误:变量u永远也不会小于0,循环条件一直成立
for (unsigned u = 10; u >= 0; --u)
std::cout << u << std::endl;
当u等于0时,继续执行for语句里的表达式。表达式--u从u当中减去1,得到的结果-1并不满足无符号数的要求,此时像所有表示范围之外的其他数字一样,-1被自动地转换成一个合法的无符号数。假设int类型占32位,则当u等于0时,--u的结果将会是4294967295.
总结:如果表达式里既有带符号类型又有无符号类型,当带符号类型取值为负时会出现异常结果,这是因为带符号数会自动地转换成无符号数。