C++学习之三、C++基本数据类型
C++ 内置数据类型分两大类:基本数据类型和复合数据类型。本编介绍基本数据类型,又称算术(arithmetic)类型。
基本数据类型——整型
整型是指没有小数部分的数字,如 2, 98, -376 和 0。术语宽度( width )用于描述存储整数时使用的内存量。使用的内存越多,则越宽。
C++ 的基本整型按宽度递增的顺序排列,分别有 char
、short
、int
、long
和 C++11 新增的 long long
,每种类型都有有符号和无符号版本,因此总共有 10 种类型可供选择。另外,ANSI/ISO C++ 还新增了一种特殊类型 bool
。
数值整型
数值型整型包括 short
、int
、long
和 C++11 新增的 long long
。
整型宽度
概念:C++ 字节由至少能够容纳实现了基本字符集的相邻位组成,也就是说 C++ 一个字节可能意味着大于 8 bit,可能为 8,16 或 32 bit,通常一个字节为 8 bit。
C++ 提供了一种灵活的标准,它确保了最小长度(从 C 语言借鉴而来):
short
至少 16 位;int
至少与short
一样长;long
至少 32 位,且至少与int
一样长;long long
至少 64 位,且至少与long
一样长。
Tips: 上述 4 种整型都有一种不能存储负数值的无符号变体,其优点是可以增大变量能够存储的最大值,只需使用关键字 unsigned
来声明即可:
1 | unsigned short n_short; // 无符号 short 类型 |
可使用运算符 sizeof
确定数据类型的宽度。
1 | cout << "int is " << sizeof (int) << " bytes.\n"; |
limits
头文件通过预编译(#define)方式,提供了一些符号常量用以确定数据类型的取值范围:
符号常量 | 表示 |
---|---|
CHAR_BIT |
char 的位数 |
CHAR_MAX |
char 的最大值 |
CHAR_MIN |
char 的最小值 |
SCHAR_MAX |
signed char 的最大值 |
SCHAR_MIN |
signed char 的最小值 |
UCHAR_MAX |
unsigned char 的最大值 |
SHRT_MAX |
short 的最大值 |
SHRT_MIN |
short 的最小值 |
USHRT_MAX |
unsigned short 的最大值 |
INT_MAX |
int 的最大值 |
INT_MIN |
int 的最小值 |
UINT_MAX |
unsigned int 的最大值 |
LONG_MAX |
long 的最大值 |
LONG_MIN |
long 的最小值 |
ULONG_MAX |
unsigned long 的最大值 |
LLONG_MAX |
long long 的最大值 |
LLONG_MIN |
long long 的最小值 |
ULLONG_MAX |
unsigned long long 的最大值 |
选择整型类型
C++ 提供了如此多的整型,使用时应该怎么去选择呢?
- 通常,
int
被设置为对目标计算机而言最为“自然”的长度,计算机处理起来效率最高。如果没有其它理由,则应使用int
。 - 如果变量表示的值不可能为负,则可以使用无符号类型,这样变量可以表示更大的值。
- 如果变量表示的整数值可能大于 16 位整数的最大值,则使用
long
。即使系统上int
为 32 位也应该这样做。这样,将程序移植到int
为 16 位的系统时,就不会突然无法正常工作。 - 如果要存储的值超过 20 亿,可使用
long long
。 - 由于
short
比int
小,使用short
可以节省内存。通常,仅当有大型整型数组时,才有必要使用short
。如果节省内存很重要,则应使用short
而不是使用int
。
整型字面值
整型字面值,常用为四种不同的计数方式:
- 十进制:第一位为 1~9,如 53
- 二进制:所有位都以 0 和 1 来表示,如 0101 等于十进制中 6
- 八进制:第一位为 0,第二位为 1~7,如 042 等于十进制中的 34
- 十六进制:以 0x 或 0X 开头,如 0x42 等于十进制的 66
进制计数只是为了人为的计数方便,在计算机中,数据最终都是以二进制存储。
Tips:
cout
输出默认为十进制,cout
提供了控制符来控制显示dec
、hex
、oct
。具体如下:1
2
3
4
5
6
7
8int a = 42;
cout << a; // 默认打印为十进制:42
cout << hex; // 切换输出为十六进制
cout << a; // 输出打印为十六进制 2a
cout << oct; // 切换输出为八进制
cout << a; // 输出打印为八进制 52
cout << dec; // 切换输出为十进制
cout << a; // 输出打印为十进制 42;C++ 如何确定常量的类型
如程序是如何确定常量 1000 是存储为
int
、long
还是其它类型呢?- 默认存储为
int
。 - 数值后的后缀。后缀有 L(Long)、U(Unsigned int)、LL(long long) 及组合后缀。
- 数值的长度。在 C++ 中,对十进制整数采用的规则与十六进制及八进制的不同。对于不带后缀的十进制整数,使用
int
、long
、long long
中能够存储该数的最小类型来表示。对于不带后缀的十六进制或八进制,使用下面几种类型中能够存储该数的最小类型来表示:int
、unsigned int
、long
、unsigned long
、long long
或unsigned long long
。
- 默认存储为
另一种整型 —— char 类型
char
是比 short
更小的整型,专为存储字符(字母或数字)而设计。它足够长,能够表示目标计算机系统中所有的基本符号——所有的字母、数字、标点符号。一般占用 8 位。
char 类型特点
char
在默认情况下既不是没有符号,也不是有符号。是否有符号由 C++
实现决定,这样编译器开发人员可以最大限度地将这种类型与硬件属性匹配起来。char
可以显示地将类型设置为 signed char
或 unsigned char
:
1 | char fodo; // 可能有符号,也可能是无符号 |
char
类型变量初始化使用单引号:char c = 'M'
C++ 将字符表示为整数,可以进行算术运算。如 char c = 'M' + 1;
使用 cin
输入时都是读取的字符,然后强转为其它类型存储。
char 字面值
- 以单引号括起来。如
'M'
、'N'
、''
、'5'
- 不能直接通过键盘输入的字符使用转义序列。如
'\a'
、'\t'
、'\n'
C++ 转义序列的编码
字符名称 | ASCII 符号 | C++ 代码 | 十进制 ASCII 编码 | 十六进制 ASCII 编码 |
---|---|---|---|---|
换行符 | NL(LF) | \n | 10 | 0xA |
水平制表符 | HT | \t | 9 | 0x9 |
垂直制表符 | VT | \v | 11 | 0xB |
退格 | BS | \b | 8 | 0x8 |
回车 | CR | \r | 13 | 0xD |
振铃 | BEL | \a | 7 | 0x7 |
反斜杠 | \ | \\ | 92 | 0x5C |
问号 | ? | \? | 63 | 0x3F |
单引号 | ‘ | \‘ | 39 | 0x27 |
双引号 | “ | \“ | 34 | 0x22 |
Tips: 应该像处理常规字符那样处理转义字符(如 \n
)。也就是说,将它们作为字符常量时,应用单引号括起来;将它们放在字符串中时,不要使用单引号。
可以基于字符的八进制和十六进制编码来使用转义序列。例如 Ctrl+Z
的 ASCII 码为 26,对应的八进制编码为 032,十六进制编码为 0x1a。可以用下面的转义序列来表示该字符:\032
或 \0x1a
。将这些编码用单引号括起,可以得到相应的字符常量。
char 引申 —— 通用字符名
C++ 实现支持基本的源字符集(可用来编写源代码的字符集),基本的执行字符集(程序执行期间可处理的字符,如换行、退格、振铃等),还有一种表示特殊字符的机制,提供扩展源字符和扩展执行字符集,它独立于任何特定的键盘,使用的是通用字符名(universal character name)。
通用字符名的用法类似于转义字符。以 \u
后面跟 4 个十六进制位 或 \U
后面跟 8 个十六进制位来表示。这些十六进制位表示的是字符的 ISO 10646
码点(一种正在制定的国际标准,为大量的字符提供数值编码)。
如果所用的实现支持扩展字符,则可以在标识符(如字符常量)和字符串中使用通用字符名。如
int k\u00F6rper;
cout << "Let them eat g\u00E2teau.\n";
ö
的 ISO 10646 码点为 00F6
,而 â
的码点 00E2
。因此,上述代码将变量名设置为 körper
,将显示下面的输出
Let them eat gâteau.
如果系统不支持 ISO 10646
,它将显示其它字符或 gu00E2teau
,而不是 â
。
char 引申 —— wchar_t 宽字符类型
wchar_t
宽字符类型是一种整数类型,它的长度和符号特征随实现而异。它有足够的空间,可以表示系统使用的最大扩展字符集。这种类型与另一种整型(底层[underlying]类型)的长度和符号属性相同。对底层类型的选择取决于实现,因此在一个系统中,它可能是 unsigned short
,而在另一个系统中,则可能是 int
。
cin
和 cout
将输入和输出看作是 char
流,因此不适于用来处理 wchar_t
类型。 iostream
头文件的最新版本提供了作用相似的工具 - wcin
和 wcout
,可用于处理 wchar_t
流。另外,可以通过加上前缀 L
来指示宽字符常量和宽字符串。
wchar_t bob = L'P'; // 宽字符常量
wcout << L"tall"; // 输出宽字符串
C++11 新增类型:char16_t 和 char32_t
区别于 wchar_t
长度及符号由实现决定,char16_t
和 char32_t
长度分别为 16 位和 32 位,无符号类型。使用前缀 u
和 U
分别来表征这两种字符或字符串常量,如 u'C'
u"work hard"
,U'R'
U"First try"
.char16_t
和 char32_t
也有底层类型 —— 一种内置的整型,但底层类型可能随系统而异。
bool 类型
ANSI/ISO C++ 标准添加了一种名叫 bool
的新类型,布尔变量的值可以是 true
或 false
,这两个值都可以通过提升转换为 int
类型,true
被转换为 1,false
被转换为 0。
bool is_ready = true;
任何数字值或指针值都可以被隐式转换为 bool 值。任何非零值都被转换为 true
,而零被转换为 false
。
基本数据类型 —— 浮点型
浮点数能够表示带小数部分的数字,如 3.14159, 23.56, 0.10 等。如果数字很大,无法表示为 long
类型,则可以使用浮点类型表示。浮点类型能够表示非常大或非常小的数,它们的内部表示方法与整数有天壤之别。浮点型由于存储方式不同,没有无符号类型。
有效位(significant figure)是指十进制数字中有意义的位(从第一个非零数字开始算起)。例如,山脉高度为 14179 英尺,该数字使用了 5 个有效位,如果写成约 14000 英尺,则该有效位只有 2 位,其余的 3 位只不过是占位符而已。
Tips: 0.00000000035 的有效位数为 2。
浮点数类型
C++ 按有效位数和允许的指数最小范围从低到高分为 3 种浮点类型:float
、double
、long double
。
浮点数有效位数
事实上,C
和 C++
对于有效位数的要求如下:
float
至少 32 位;double
至少 48 位,且不少于float
;long double
至少和double
一样多;- 以上三种类型的有效位数可以一样多。然而,通常,
float
为 32 位,double
为 64 位,long double
为 80、96 或 128 位。 - 以上三种类型的指数范围至少是 -37 到 37。
头文件 cfloat
或 float.h
对系统的限制作了说明(cfloat
是 C 语言的 float.h
文件的 C++ 版本)。下面列出 Borland C++ Builder
的 float.h
文件中一些批注项:
1 | // 以下为对浮点型有效位的限制 |
浮点数字面值
在程序中书写浮点常量时,程序将把它存储为哪种浮点类型呢?
- 默认情况下,浮点常量将存储为
double
类型。
如8.3 0.14 0.1e7 3.99e-5
默认都是double
类型 - 使用后缀存储为指定类型。
float
后缀为f
或F
,long double
后缀为l
或L
。1
2
3
41.234f // float 常量
2.3E20F // float 常量
2.2L // long double 常量
2.2 // 默认为 double 常量
浮点数优缺点
与整数相比,浮点数有两大优点。首先,它们可以表示整数之间的值。其次,由于有缩放因子,它们可以表示更大的范围。缺点方面,浮点运算的速度通常比整数运算慢,且精度将降低。
一些总结归纳
数值整型和浮点型字面值,使用后缀来表征不同类型,如 10U, 100UL 。但对于 char 类型,使用前缀来表征不同的类型,如 u'a'
U'a'
L'b'
。