第二章 变量和基本类型
数据类型是程序的基础:它告诉我们数据的意义以及我们能在数据上执行的操作
C++语言定义了几种基本内置类型(如字符,整型,浮点数等),同时也提供了自定义数据类型的机制。基于此,C++标准库定义了一些更加复杂的数据类型,比如可边长字符串和向量等。
2.1 基本内置类型
C++ 定义了一组包括 整数、浮点数、单个字符 和 布尔值 的算术类型,另外还定义了一种称为 void 的空类型(空类型不对应具体的值,仅用于一些特殊场合,如:当函数不返回任何值时使用空类型作为返回类型)。
2.1.1 算术类型
算术类型分为:整型(包括字符和布尔类型)和浮点型
算数类型的尺寸依机器而定。下表列出了C++标准规定的尺寸的最小值。
类型 | 含义 | 最小尺寸 |
---|---|---|
bool | 布尔类型 | 未定义 |
char | 字符 | 8位 |
wchar_t | 宽字符 | 16位 |
char16_t | Unicode字符 | 16位 |
char32_t | Unicode字符 | 32位 |
short | 短整型 | 16位 |
int | 整型 | 16位 |
long | 长整型 | 32位 |
long long | 长整型 | 64位 |
float | 单精度浮点数 | 6位有效数字 |
double | 双精度浮点数 | 10位有效数字 |
long double | 扩展精度浮点数 | 10位有效数字 |
- 布尔类型的取值是真(true)或者假(false)
- 一个char类型的大小和一个机器字节(byte)一样
- 其他字符类型用于扩展字符集,如wchar_t、char16_t、char32_t。
- wchar_t类型用于确保可以存放机器最大扩展字符集中的任意一个字符
- char16_t、char32_t为Unicode字符集服务(Unicode是用于表示所有自然语言中字符的标准)。
- 对于其他整型类型,C++语言规定:short ≤ int≤ long ≤ long long(
long long
是C++11新定义的类型)。
大多数计算机以2的整数次幂个比特作为块来处理内存,可寻址的最小内存块称为“字节(byte)”;存储的基本单元称为“字(word)”,通常由几个字节组成。
在C++语言中,一个字节要至少能容纳机器基本字符集中的字符。大多数机器的字节由8比特构成,字则由32或64比特构成,也就是4或8字节。
字 > 字节 > 比特
为了赋予内存中某个地址明确的含义,必须首先知道存储在该地址的数据的类型
- 浮点型可表示单精度、双精度和扩展精度值。通常,float以一个字(32比特)来表示,double以两个字(64比特)来表示,long double以 三或四个字(96或128比特)来表示。
带符号类型和无符号类型
- 除去布尔型和扩展的字符型之外,其他整型可划分为 带符号的(signed)和无符号的(unsigned) 两种。
- 类型
short
、int
、long
和long long
都是带符号的,无符号型必须在这些类型名前添加unsigned
。 - 同其他整型不同,字符型被分为三种:
char
、signed char
、和unsigned char
。但是表现形式只有带符号和无符号两种。类型char
和signed char
并不一样,char
的具体形式由编译器(compiler)决定。
- 类型
- 无符号类型中所有比特都用来存储值,如:8比特的
unsigned char
可以表示0~255区间内的值。 - C++标准没有规定带符号类型应如何表示,但约定了在表示范围内正值和负值的量应平衡。因此,8比特的
signed char
理论上应该可以表示-127至127区间内的值,大多数现代计算机将实际的表示范围定为-128至127。
如何选择算数类型:
- 当明确知晓数值不可能为负时,应该使用无符号类型。
- 使用
int
执行整数运算,不易出错。如果数值超过了int
的表示范围,应该使用long long
类型。- 在算数表达式中不要使用
char
和bool
类型,只有在存放字符或布尔值时才使用它们(因为char类型在一些机器上是有符号的,而在另外一些机器上又是无符号的,所以如果使用char进行运算特别容易出问题)。如果需要使用一个不大的整数,应该明确指定它的类型是signed char
还是unsigned char
。- 执行浮点数运算时建议使用
double
类型(因为float通常精度不够而且双精度浮点数和单精度浮点数的计算代价相差无几,甚至在某些机器上双精度运算比单精度快)。
2.1.2 类型转换
当在程序的某处我们使用了一种类型而其实对象应该取另一种类型时,程序会自动进行类型转换。
类型所能表示的值的范围决定了转换的过程:
- 把非布尔类型的算术值赋给布尔类型时,初始值为0则结果为
false
,否则结果为true
。 - 把布尔值赋给非布尔类型时,初始值为
false
则结果为0,初始值为true
则结果为1。 - 把浮点数赋给整数类型时,进行近似处理,结果值仅保留浮点数中的整数部分。
- 把整数值赋给浮点类型时,小数部分记为0。如果该整数所占的空间超过了浮点类型的容量,精度可能有损失。
- 当赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数。例如:8比特大小的
unsigned char
能表示的数值总数是256(可表示0~255区间内的值),当我们把-1赋给该类型型时,所得结果是255。(见P33) - 赋给带符号类型一个超出它表示范围的值时,结果是 未定义的(undefined)。
建议:避免无法预知和依赖于实现环境的行为。
含有无符号类型的表达式
提示:切勿混用带符号类型和无符号类型
如果表达式里既有带符号类型又有无符号类型,当带符号类型取值为负时会出现异常结果,这是因为带符号数会自动地转换成无符号数(P34~35)。
无符号数不会小于0这一事实关系到循环的写法。
//错误:变量u永远也不会小于0,循环条件一直成立
for(unsigned u = 10; u >= 0; --u)
std::cout << u <<std::endl;
一种解决办法是用 while 语句来代替 for 语句,因为前者可以在输出变量前先减去1。
unsigned u = 11; //从确定要打印的 最大数+1 的数开始
while (u > 0)
{
--u; //先减1,这样最后一次迭代将打印0
std::cout << u << std::endl;
}
2.1.3 字面值常量
每个字面值常量都对应一种数据类型,字面值常量的形式和值决定了它的数据类型。
整型和浮点型字面值
可以将整型字面值写作十进制数、八进制数或十六进制数的形式。
- 以
0
开头的整数代表八进制数 - 以
0x
或0X
开头的代表十六进制数
整型字面值具体的数据类型由它的值和符号决定。默认情况下,十进制字面值是带符号数,八进制和十六进制字面值既可能是带符号的也可能是无符号的。
- 十进制字面值的类型是能容纳下当前的值的
int、long和long long
中尺寸最小的那个。 - 八进制和十六进制字面值类型是能容纳其数值的
int
、unsigned int
、long
、unsigned long
、long long
和unsigned long long
中尺寸最小着。
如果一个字面值连与之关联的最大的数据类型都放不下,将产生错误。
尽管整型字面值可以存储在带符号数据类型中,但严格来说,十进制字面值不会是负数(符号并不在字面值之内,它的作用仅仅是对字面值取负值而已)。
浮点型字面值表现为一个小数或以科学计数法表示的指数,其中指数部分用 E 或 e 标识。
- 默认的,浮点型字面值是一个double
后面会介绍用后缀代表相应的字面值类型。
字符和字符串字面值
由单引号括起来的一个字符称为char型字面值,双引号括起来的零个或多个字符构成字符串型字面值(字符串字面值的类型实际上是由常量字符构成的数组(array))。
编译器在每个字符串的结尾处添加一个空字符(