C++ Primer 类型转换

2.1.2 类型转换

是一种运算。

对象的类型定义了对象能包含的数据和能参与的运算,其中一种运算被大多数类型支持,就是将对象从一种给定的类型 转换(convert) 为另一种类型。

当程序的某处使用了一种类型而其实对象应该是取另一种类型时,程序会自动进行类型转换(4.11节 第141页更详细的介绍)。当某种类型的对象强行赋了另一种类型的值时:

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比特,c2的值是未定义的

类型所能表示的值的范围决定了转换的过程:

  • 非布尔类型赋给布尔类型,初始值为0结果为false,否则结果为true
  • 布尔值赋给整数类型,初始值为false则结果为0,初始值为true则结果为1。
  • 浮点数赋给整数类型,进行了近似处理。结果值将保留浮点数中小数点之前的部分。
  • 赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数。例如,比特大小的unsigned char可以表示0-255区间内的值,如果赋了一个区间以外的值,则实际的结果是该值对256取模后的余数。因此,把-1赋给8比特大小的unsigned char所得的结果是255。
  • 赋给带符号类型一个超出它表示范围的值时,结果是 未定义的(undefined)。此时,程序可能继续工作、可能崩溃、也可能生成垃圾数据。

纪律:避免无法预知和依赖于实现环境的行为(禁止出现未定义的行为!)

无法预知的行为源于编译器无需(有时也不能)检测的错误。即使代码编译通过了,如果程序执行了一条未定义的表达式,仍有可能产生错误。

不幸的是,在某些情况和/或某些编译器下,含有无法预知行为的程序也能正确运行。但是我们却无法保证同样一个程序在别的编译器下能正常工作,甚至已经编译通过的代码再次执行也可能会报错。此外,也不能认为这样的程序对一组输入有效,对另一组输入就一定有效。

程序也应该尽量避免依赖于实现环境的行为。如果我们把int的尺寸看成时一个确定不变的已知值,那么这样的程序就称作 不可移植的(nonportable)当程序移植到别的机器上后,依赖于实现环境的程序就可能发生错误。要从过去的代码中定位这类错误可不是一件轻松愉快的工作。

当在程序的某处使用了一种算数类型的值而其实所需的是另一种类型的值时,编译器同样会执行类型转换。

int i = 42;
if (i)     // if条件的值为true i被自动地转换成布尔值
    i = 0;

如果 i 的值为0,则条件的值为false,i 的所有其他取值(非0)都将使条件为true

含有无符号类型的表达式

当一个算数表达式中既有无符号数又有int值时,那个int值就会转换成无符号数。

unsigned u = 10;
int i = -42;
std::cout << i + i << std::endl;  //输出-84
std::cout << u + i << std::endl;  //如果int占32位,输出4294967264 相加前首先把整数-42转换成无符号数

当从无符号数中减去一个值时,不管这个值是不是无符号数,都必须确保结果不能是一个负值:

unsigned u1 = 42, u2 = 10;
std::cout << u1 - u2 << std::endl;  //正确:输出32
std::cout << u2 - u1 << std::endl;  //正确:不过,结果是取模后的值

无符号数不会小于0这一事实同样关系到循环的写法。下面例子把从10到0的数字降序输出。

//错误:变量u永远也不会小于0,循环条件一直成立
for (unsigned u = 10; u >= 0; --i)
    std::cout << i << std::endl;

当 u 等于0时,这次迭代输出0,然后继续执行for语句里的表达式。表达式 --u 从 u 当中减去1,得到的结果-1并不满足无符号数的要求,-1被自动地转换成一个合法的无符号数。假设int类型占32位,则当 u 等于0时, --u 的结果将会是4294967295。

一种解决办法是,用while语句来代替for语句,因为前者让我们能够在输出变量之前(而非之后)先减去1:

unsigned u = 11; //确定要输出的最大数,从比它大1的数开始
while (u > 0)
{
    --u;         //先减1,这样最后一次迭代时就会输出0
    std::cout << u << std::endl;
}

改写后的循环先执行对循环控制变量减1的操作,这样最后一次迭代时,进入循环的 u 值为1。此时将其减1,则这次迭代输出的数就是0;下一次再检查循环条件时,u 的值等于0而无法再进入循环。因为要先做-1的操作,所以初始化 u 的值因该要比输出的最大值大1。这里,u 初始化为11,输出的最大数是10。

提示:切勿混用带符号类型和无符号类型

如果表达式里既有带符号类型又有无符号类型,编译器会永远将其变成无符号再说。当带符号类型取值为负时会出现异常结果,这是因为带符号数会自动地转换成无符号数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值