前言
- 1)当我们给无符号类型的变量赋值一个超出表示它表示范围的值时,结果是初始值对范围总数取模后的余数。如下图,unsigned
short为2,占两个字节,则范围为0~65535。所以-1取模(-1+65536)后值就为65535
std::cout << sizeof(unsigned short) << std::endl;
unsigned short i = -1;
std::cout << i << std::endl;
- 2)当我们赋给带符号类型一个超出它范围的值时,结果是未定义的(undefined)。此时,程序可能会继续工作、可能崩溃,也可能生成垃圾数据。(见C++
primer第5版2.1.2 P33)
隐式转换
先看下面的式子有几次隐式的类型转换?
答案是两次。
第一次发生在相加的运算中。C++不会直接将两个不同的类型的值相加,并且算术类型之间的隐式转换被设计的尽可能避免损失精度。(C++ primer 第5版 4.11 P141)。所以整型会被转为double形:3->3.0,然后和3.541加。
第二次发生在初始化阶段。因为变量的类型已经固定,所以初始化的值被转换为变量的类型。既6.541->6给ival。
何时发生隐式类型转换(C++ primer 第5版 4.11 P141)
算术转换
含义:将一种算术类型转换为另一种算术类型。如前面的所述的3+3.541转换为3.0+3.541。
整型提升:
含义是将小的整型提升为大的整型。既char、short、unsigned short、bool、signed char、unsigned char等较小的数据类型会转换为int型。但是注意,这种提升的前提是小数据类型的范围在int范围类型内
。一旦不在范围内,则提升为unsigned int。比如在某些系统中unsigned short和int占同样的字节,此时, unsigned short就转换为unsigned int,而不是int。
下面介绍算数类型转换的规则:
- 首先按“整型提升”规则,将小于int型的整型提升为int型。
- “整型提升”之后的两个对象
都是无符号或者都是带符号
。同类型则直接计算,否则小类型转换为大类型。
char cval;
short sval;
int ival;
long lval;
定义了以上的变量,则
计算cval+sval:先把两个都提升为int型,为同类型,计算;
计算sval+ival:先把sval提升为int型,为同类型,计算;
计算cval+lval:将cval提升为int型,int和long都为带符号但不同类型。则小转大,int转换为long型后再计算。
- “整型提升”之后,两个对象
一个无符号一个有符号
,此类情况较复杂,需分类讨论:
情况1:若无符号的不小于带符号的,将有符号的转换为无符号的,示意图如下:
std::cout <<"sizeof(int) = "<< sizeof(int) << std::endl;
std::cout << "sizeof(long long) = " << sizeof(long long) << std::endl;
unsigned int ui = 10; //无符号的大小为4
unsigned long long l = 50; //无符号的大小为8
int i = -42; //带符号的大小为4
std::cout << "typeid(unsigned long long).name():" << typeid(unsigned long long).name() << std::endl;
std::cout << "typeid(i + ui).name():"<<typeid(i + ui).name() << std::endl;
std::cout << "typeid(i + l).name():" << typeid(i + l).name() << std::endl;
从上面的例子可以看到:unsigned int 和int做计算时,转换为unsigned int计算。unsigned long long 和 int 做计算时,转换为unsigned long long计算。
情况2:若带符号大于无符号的,此时分情况讨论:
- i.若无符号的都在有符号的范围内,则无符号的转为有符号的,示意图如下:
std::cout <<"sizeof(int) = "<< sizeof(int) << std::endl;
std::cout << "sizeof(long long) = " << sizeof(long long) << std::endl;
unsigned int ui = 10; //无符号的大小为4
long long l = -50; //带符号的大小为8
std::cout << "typeid(long long).name():" << typeid(long long).name() << std::endl;
std::cout << "typeid(ui + l).name():"<<typeid(ui + l).name() << std::endl;
从上面的例子可以看出,当带符号的大小>不带符号的大小,并且不带符号的全部范围都在带符号的范围内时,unsigned int转为long long型。
- ii.若无符号的有不在有符号的范围内的,那么带符号的转换为无符号的,示意图如下: