C++定义了一套包含算数类型和空类型(void)在内的基本数据类型。其中算数类型包含了字符、整型数、布尔值和浮点数。空类型不对应具体的值,仅用于一些特殊的场合,例如最常见的是,当函数不需要返回值时使用空类型最为返回类型
算数类型的尺寸在不同的机器上有所差别,表2.1中列出了C++标准规定尺寸的最小值,同时允许编译器为这些类型赋予更大的尺寸。某一类型所占的比特数不同,所能表示的数据范围也不一样
带符号类型和无符号类型
除去布尔型和扩展的字符型之外,其他整型都可以划分为带符号的和无符号的两种。带符号类型可以表示正数、负数或0,无符号数仅能表示大于或等于0的数。
类型int、short、long和long long都是带符号的,通过在这些类型名前添加unsigned就可以得到无符号类型,例如unsigned long。类型unsigned int可以缩写成unsigned。无符号类型的比特都用来存储值。例如8比特的unsigned char可以表示0值255区间内的值。
建议:如何选择类型
1、当明确知晓数值不可能为负值时,选用无符号数
2、使用int进行整型运算。
3、在算数表达式中不要使用char或bool,只有在存放字符或布尔值时才使用他们。因为类型char在一些机器上是有符号的,而在另外一些机器上是无符号的,如果使用char运算的话,容易出问题。如果需要使用一个不大的整数,那么明确指定他的类型是signed char或者unsigned char。
4、执行浮点数运算用double。一般而言float的精度不够,而且双精度浮点数和单精度浮点数在计算上的代价相差无几。甚至在某些机器上,双精度运算比单精度还要快
类型转换
当在程序中的某处我们使用了一种类型而其实对象应该是另一种类型时,程序会自动的进行类型转换。这里说明一下,当给某种类型的对象强行赋了另一种类型的值时,会发生什么。
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的值时未定义的
类型所能表示的值的范围决定了转换的过程:
1、当我们把一个非布尔类型的算数值赋给布尔类型时,初始值为0则结果为false,否则结果为true
2、当我们把一个布尔类型的算数值赋给非布尔类型时,初始值为false则结果为0,初始值为true则结果为1
3、当我们把一个浮点数赋给整数类型时,进行了近似处理。结果值将仅保留浮点数中小数点前面的部分
4、当我们把一个整数值赋给一个浮点类型时,小数部分记为0.如果该整数所占空间查过了浮点类型的容量,精度可能会有损失
5、当我们赋给无符号类型一个超出他表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数。例如,8比特大小的unsigned char可以表示0至255区间的值,如果我们赋了一个区间意外的值,则实际结果是该值对256取模后所得的余数,因此把-1赋给8比特大小的unsigned char所得的结果是255(2^8-1)
6、当我们赋值给带符号类型一个超出他表示范围的值时,结果是未定义的。程序可能继续工作,可能崩溃也可能产生垃圾数据。
含有无符号类型的表达式
尽管我们不会故意给一个无符号对象赋一个负值,却可能写出这么做的代码。例如下面的代码:
unsigned u=10;
int i=-42;
cout<<i+i<<endl;
cout<<u+i<<endl;
第一个表达式里连个负数相加得到-84,没问题;但是第二个式子里,在相加前要把整数-42转换成无符号数。所以在第二个表达式里,i实际上等于2^32-42,u+i的结果为4294967264.
当从无符号数中减去一个值时,不管这个值是不是无符号数,我们都必须确保结果不能是一个负值;
无符号数不会小于0这一事实同样会关系到循环的写法。例如下面的循环:
for(int i=10;i>=0;i--)
cout<<i<<endl;
可能会觉得反正也不打算输出负数,可以用无符号数来重写这个循环。然而这个不经意的改变却会带来死循环。
for(unsigned u=10;u>=0;u--)
cout<<u<<endl;
当u=0时,继续执行for循环语句,表达式u--之后,u=-1,但是u是无符号数,不能表示-1,根据无符号数的赋负值时的运算方式,可以得到此时u的实际值为2^32-1=4294967295.因此该循环语句将会一直循环下去。如图:
提示 :切勿混用带符号类型和无符号类型