本章讲解C++内置的数据类型(如:字符、整型、浮点数等)和自定义数据类型的机制。下一章讲解C++标准库里面定义的更加复杂的数据类型,比如可变长字符串和向量等。
C++内置的基本类型包括:算术类型和空类型。算术类型值:字符、整型数、布尔值和浮点数;空类型对对应具体的值,仅用void表示用在一些特俗场合,比如函数不返回任何值时,就使用void作为返回类型。
算术类型分类整型和浮点型。
各算术类型在不同机器上表示的数字范围不一样,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位有效数字 |
其中:char的大小为一个字节,用于存放英语体系里面的任意字符;布尔类型的取值是真(true)或假(false);
内置类型的机器实现:
计算机按照二进制序列连续存储数据,每个bit非0即1,例如:
00001011110110101101011100001111......
只有将连续的一段bit规定为一个单位,二进制数据才有意义。C++规定,一个字节至少要能容纳机器中基本字符的所有字符。所以,一个字节有8位bit组成,一个字由32或64位bit组成。
由此,计算机中每8个bit使用1个地址,如下所示:
地址 数据 736424 1 0 1 0 0 1 1 0 736425 1 0 0 1 0 0 0 1 736426 1 1 1 0 1 1 1 0 736427 0 1 1 0 0 0 0 1 数据类型决定了某个具体数据所占的比特数以及这些比特位上数字的含义。
浮点型在C++中,被指定了最小有效位数,但是大多数编译器都实现了更高的精度。
除布尔型和扩展的字符型以外,其他整型可以划分为带符号(signed)和无符号(unsigned)的两种类型。带符号类型可以表示正数、负数或0;无符号类型仅能表示正数或0,写法如下:
unsigned int、unsigned long、unsigned char。
如果int、short、long和long long没有表示是否带符号,则默认是带有符号的,可以表示负数。
注意:浮点型是不能用unsigned和signed修饰的。
C++在类型的规定上有如此多的类型和规定,就是为了尽可能接近硬件,满足各种硬件的特性,所以显得有些繁杂。
注意:
切勿混用带符号类型和无符号类型,否则发生错误,运算结果无意义。
数据类型的的定义,决定了能包含的数据范围和运算。但是当代码中值与数据类型不匹配时,C++会进行自动数据类型转换。
bool b = 42 // b为真
int i = b; // i的值为1
i = 3.14; // i的值为3
double pi = i; // pi的值为3.0
把非布尔值赋值给布尔类型,0表示false,非0表示true;
把布尔值赋值给非布尔类型,false表示0,true表示1;
浮点数赋值给整型,仅保留整数部分;
整数赋值给浮点数,小数部分为0。如果整数过大,超过浮点类型容量,真数据失真;
每种数据类型的值,可以在程序中直接写出,被称作字面常量,比如:42。
每个字面常量都对应一种数据类型,其形式和值决定了它的数据类型。
数字可以是十进制、八进制、十六进制,为了区分这几种字面常量的不同,八进制和十六进制需要加前缀符号0和0X、0x,如下:
20 十进制 024 八进制 0x24十六进制 0X24十六进制
数字的字面常量,C++会以数字的大小,找到最小限度能装下该字面常量的数据类型与之匹配。整型经常是int型,但int装不下时,可能是long型;浮点型经常默认是double型。
字符字面值由单引号括起来,且只能写一个字符,比如'C';
字符串字面值由双引号括起来,里面可以写很多字符,本质上是由每一个字符所组成的数组,并以空字符('\0')表示结尾。所以,即使字符串里面只有一个字符,比如“C”,依然长度是两个字符,字符'C'和空字符。
两个字符串字面值写在一起,哪怕中间有空白字符(空格符、缩进符、换行符),也被C++认为是一个字符串,所以当书写较长的字符串时,一行不合适,可以分为两个字符串放在两行。
在字符串中,有两类字符不能直接使用,必须使用转义字符进行转义后才能使用。这两类字符是:
1.不可打印的字符,如退格、换行、空格或其它控制字符,因为没有可视化的符号;
2.在C++中有特殊含义的字符,如单引号、双引号、反斜杠、问号。
C++中转义字符如下:
换行符 \n | 问号 \? |
纵向制表符 \v | 进纸符 \f |
反斜杠 \\ | 报警符 \a |
回车 \r | 双引号 \" |
横向制表符 \t | 单引号 \' |
退格符 \b |
还有一种泛化的转义字符:格式1为:"\1到3个8进制数字";格式2为:“\x1到多个十六进制数字”,比如:
\7 响铃 \12 换行符 \40 空格 \0 空字符 \115 字符M \x4d 字符M
通过给字面值加上指定前缀和后缀,可以强制规定字面值的数据类型;
前缀 | 含义 | 类型 |
---|---|---|
u | Unicode 16位字符 | chart16_t |
U | Unicode 32位字符 | chart32_t |
L | 宽字符 | wchar_t |
u8 | UTF-8(仅用于字符串字面常量) | char |
后缀 | 最小匹配类型 |
u 或者 U | unsigned |
l 或者 L | long |
ll 或者 LL | long long |
后缀 | 类型 |
f 或者 F | float |
l 或者 L | long double |
布尔类型的字面值是:true和false;
指针字面值是:nullptr。
变量是一个有名称的、可供程序操作的存储空间。C++中的每个变量都有其数据类型,数据类型决定了变量所占内存空间的大小和布局方式、能存储的值的范围,以及变量能够参与的运算规则。
变量定义的基本格式是:
数据类型说明符 变量名1, 变量名2, 变量名3 ...... ;
int a = 0, b, c=0; // a 和 c初始化了,b仅仅只是定义了
当变量获取第一个值的时候,称为初始化。初始化的值可以是任意形式:字面值常量、表达式结果、函数返回值等。
一条语句中初始化多个变量,前面的变量可以马上为后面的变量初始化。
double a = 0.1, b = a; // a 和 b的值都是0.1
注意:
初始化不是赋值,初始化的含义是创建变量时规定一个最初的值,而赋值是把变量当前的值擦除,用一个新的值代替。二者在内存中的操作动作不一样。
在C++ 11中引入,用花括号或括号初始化变量,如下都是正确的:
// 以下变量值都是0
int a = 0;
int b = {0};
int c{0};
int d(0);
其中,花括号的形式逐渐流行,无论初始化还是赋值,都可以使用花括号。
如果定义变量时没有初始化,则变量被默认初始化,给赋予默认值。如果在函数体的变量没有初始化,则默认为0;如果在函数体内,如果变量没有初始化且没有赋值,则该变量值不可控,所以函数体内的变量一定要初始化或赋值。