1. 内存 #
1.1 bool 变量 #
在之前的课程中,我们学习了 bool 变量。
我们说过,bool 变量的取值范围,是 0 或者 1。(也就是 false 和 true)
现在,大家看,这不就是一个“二进制”吗?
1.2 为什么计算机选择了二进制? #
其实,这和我们之前讲到的内存,息息相关。
大家还记得吗,内存有一个很重要的特点,就是
断电之后,数据就丢失了。
为什么呢?
这其实啊,这是因为,在内存中,有很多的内存小单元。每个小单元,可以存储一定的电荷。
内存里面的样子,就如下图所示:
我们程序中用到的所有数据,无论是电影、音乐、文件,甚至是我们现在看到的画面,
其实,都是以内存中的某些小单元的“有电/没电”状态,来存储的。
这样,断电以后,所有的小单元都变成了“没电”状态,那当然数据就丢失了。
我们的“数据/信息”,在电脑中,其实就是小单元们的“有电/没电”状态;
“有电/没电”状态,需要电源供电,才可以保持;
或许大家有疑问,为什么我们存放在电脑上的文件,不会因为关机,而丢失呢?
我们的存在电脑的文件,之所以不丢失,是因为它们是存放在硬盘上的。
硬盘的存储技术和内存不同,硬盘在断电后,可以保留数据。
内存的这种存储技术,比硬盘读写速度快;这样程序才不会卡。
所以,一般将硬盘用于存储数据,内存用于运行程序。
1.3 内存的模型 #
学习 C++ 的过程中,需要一直和内存打交道。所以为了讨论方便,我们一般将内存画作下面的样子。“有电/没电”状态,用“1/0”表示。
假如,将上图的“有电/没电”状态,写成二进制数的话,请问要怎么写?(请从左边开始,写 8 位即可)
1011 0010
请将其转化成 16 进制数,10 进制数。
0xB2 178(10进制)
我们可以做一个合理的假设,假如我们运行了下面的代码:
int a; a = 178;
那么,这就是变量 a,赋值为 178 后,在内存中的样子。
(当然,这个说法其实不够准确。因为 int 是“很长”的。)
1.4 一个 int #
下图中,两端灰色中间的部分,是一个 int 的长度。所以,这才是上面的例程中的变量 a 在内存中的样子。
请数一数,一个 int 变量的长度,是一个 “bool” 变量的几倍?
答案是 32。
1.5 数据的单位 #

1.5.1 单位 #
计算机世界的数据大小,也和物理世界的长度一样,有自己的单位。
数据的最小单位是“位”(Bit),也就是一个 bool 变量所占的空间。
不过,由于“位”(Bit)太小,在使用上,我们习惯用另一个单位“字节”(Byte,简称 B),作为最小单位。
1 Byte = 8 Bits 1 字节 = 8 位
上一节课,我们计算了一个 int 的大小,是 bool 的 32 倍。
所以,一个 int 的大小是 4 字节。
除此以外,还有如下的常用单位:
1 KB = 1024 B // 下载速度,一般为:几百 KB/s 1 MB = 1024 KB // 一首歌曲的大小,一般为:几十 MB 1 GB = 1024 MB // 一部电影的大小,一般为:几 GB 1 TB = 1024 GB // 一些电脑的硬盘总容量为:几 TB
1.5.2 单位换算 #
在上面的描述中,需要特别注意的是单位间的比例,是 1024。
这里的 1024,是 2^10 。这也是和二进制有关。
1.6 常见数据类型的长度(32位操作系统为例) #
在不同的操作系统下,数据类型的长度会有差异。这里以 32 bit 的操作系统为例说明:
1.6.1 整型 #
类型名称 | short | int | long | long long | unsigned short | unsigned int | unsigned long | unsigned long long |
所占字节数 | 2 Bytes | 4 Bytes | 4 Bytes | 8 Bytes | 2 Bytes | 4 Bytes | 4 Bytes | 8 Bytes |
表示范围 | -32768~32767 | -2147483648~ 2147483647 | -2147483648~ 2147483647 | -9223372036854775808~ 9223372036854775807 | 0~65535 | 0~ 4294967295 | 0~ 4294967295 | 0~ 18446744073709551615 |
表示范围(十六进制) | 0x0000~0xFFFF | 0x00000000~ 0xFFFFFFFF | 0x00000000~ 0xFFFFFFFF | 0x0000000000000000~ 0xFFFFFFFFFFFFFFFF | 0x0000~0xFFFF | 0x00000000~ 0xFFFFFFFF | 0x00000000~ 0xFFFFFFFF | 0x0000000000000000~ 0xFFFFFFFFFFFFFFFF |
- 十六进制的两位,占据 1 Byte;
- 只有 unsigned 类型,十六进制的表示范围,和十进制的表示范围,是一一对应的;
1.6.2 实型 #
类型名称 | float(中文翻译:单精度) | double(中文翻译:双精度) | long double | bool |
所占字节数 | 4 Bytes | 8 Bytes | 16 Bytes | * 1(=8 Bits) Byte,见说明 |
表示范围 | -3.4E+38~3.4E+38 | -1.7E+308~1.7E+308 | -3.4E4932~3.4E4932 | true / false |
表示范围(十六进制) | 0x00000000~ 0xFFFFFFFF | 0x0000000000000000~ 0xFFFFFFFFFFFFFFFF | 0x0~ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
在C++中,bool 其实也是占一个字节(8 位)。这是比较特殊的地方。
1.6.3 字符型 #
- 字符型还未介绍,将在后续章节讲解。
类型名称 | char | unsigned char |
所占字节数 | 1 Byte | 1 Byte |
表示范围 | -128~127 | 0~255 |
表示范围(十六进制) | 0x00~ 0xFF | 0x00~ 0xFF |
由于,在不同机器上,数据的长度会有不同。所以,C++ 给了一个方法,用于查询变量(或者类型)的长度,单位“字节 Bytes”。
cout << sizeof(int) << " Bytes" << endl; cout << sizeof(float) << " Bytes" << endl; cout << sizeof(double) << " Bytes" << endl; cout << sizeof(short) << " Bytes" << endl; cout << sizeof(unsigned int) << " Bytes" << endl; int a(5); cout << sizeof(a) << " Bytes" << endl;
2. 数据类型转化 #
2.1 不同数据类型的长度(以 32 位操作系统为例) #
2.1.1 各个数据类型长度一览 #
- 1 Bit: bool

- 1 Byte: char, unsigned char

- 2 Bytes: short, unsigned short

- 4 Bytes: int, unsigned int, long, unsigned long, float

- 8 Bytes: long long, unsigned long long, double


- 16 Bytes: long double




2.1.2 有符号/无符号的差别 #
- 无符号
unsigned short

- 有符号
short
这里的第一位,是定位为“符号位”。
这里为 0 ,则表示非负数(没有符号);
这里为 1 ,则表示负数(有符号);
2.2 隐式(自动)类型转化 #
看了不同数据类型的长度后,我们回过头来思考这样的一个问题:
2.2.1 规则一 #
以下表达式的计算结果是什么?
short a_s = 1; int a_i = 1; ____ a_r1 = a_s + a_i; float a_f = 0.1; double a_d = 3.14; ____ a_r2 = a_f + a_d; ____ a_r3 = a_i + a_d;
像这样的问题,涉及到的是 C++ 中数据类型的互相转化的规则。
C++ 中,包含了一些自动转化的规则,详述如下:
- 低精度(长度短) -> 高精度(长度长)
上面的计算结果是
short a_s = 1; int a_i = 1; _int_ a_r1 = a_s + a_i; // 这里应该填 int。因为 int 占 4 字节,short 占 2 字节。 float a_f = 0.1; double a_d = 3.14; _double_ a_r2 = a_f + a_d; // 这里应该填 double。因为 float 占 4 字节,double 占 8 字节。 _double_ a_r3 = a_i + a_d; // 这里应该填 double。因为 int 占 4 字节,double 占 8 字节。
2.2.2 规则二 #
再请看:
int a_i = 1; unsigned int a_ui = 1; ____ a_r = a_i + a_ui;
- 规则二:有符号 -> 无符号
上面的计算结果是
int a_i = 1; unsigned int a_ui = 1; _unsigned int_ a_r = a_i + a_ui; // 这里应该填 unsigned int。有符号转化为无符号
2.2.3 规则三 #
再请看:
int a_i = 1; float a_f = 0.1; ____ a_r3 = a_i + a_f;
- 规则三:整型 -> 浮点型
上面的计算结果是
int a_i = 1; float a_f = 0.1; _float_ a_r3 = a_i + a_f; // 这里应该填 float。因为 int 占 4 字节,float 占 4 字节。
2.2.4 隐式类型转化 – 小结 #
隐式类型转换方向:
bool -> char -> unsigned char -> short -> unsigned short -> int -> unsigned int -> long -> unsigned long -> float -> double -> long double
2.3 显式(强制)类型转化 #
什么是“ 显式类型转化”?其实就是上述过程的“逆过程”。
但是,逆过程可能会带来额外的问题。
2.3.1 十六进制的好处 #
我们首先定义两个变量,随意赋值。
unsigned short a_s; unsigned int a_i; a_s = 0xF0F0; // 十六进制的 1 位,对应二进制的 4 位。 a_i = 0xF0F0A010 // 在分析问题是,能带来很多方便。
这里稍微提一下,十六进制表示的重要性。
1111 0000 1111 0000 (2进制) 0x F 0 F 0; 从二进制中,可以直接看出来,内存中的“有电没电”状态。 而十六进制的每 1 位,正好对应二进制的 4 位。 故而,用十六进制表达,既可以较为直观的看出内存状态,也较为简洁。
2.3.2 数据截断 #
这时,假如将 “数据长度较长的 a_i” 赋值给 “数据长度较短的 a_s” 会发生什么呢?
a_i; // 0xF0F0A010 a_s; // 0xF0F0; a_s = a_i;
很显然,小容量的空间,存储不了大数据。
所以,本来完整的数据,只能被“拦腰折断”!那么,就会发生问题。
当程序中,需要做这样的转化时,必须要特别注意。
应该遵守这样的原则:
赋值的值 不能超过 被赋值变量类型的表示范围。
小数 转化成整数,仅仅保留整数部分(不是四舍五入,而是直接取整数部分)。
2.3.3 数据类型的表示范围 #
常见数据类型的长度(Win32为例)
在不同的操作系统下,数据类型的长度会有差异。这里以 32 bit 的操作系统为例说明:
整型
类型名称 | short | int | long | long long | unsigned short | unsigned int | unsigned long | unsigned long long |
所占字节数 | 2 Bytes | 4 Bytes | 4 Bytes | 8 Bytes | 2 Bytes | 4 Bytes | 4 Bytes | 8 Bytes |
表示范围 | -32768~32767 | -2147483648~ 2147483647 | -2147483648~ 2147483647 | -9223372036854775808~ 9223372036854775807 | 0~65535 | 0~ 4294967295 | 0~ 4294967295 | 0~ 18446744073709551615 |
表示范围(十六进制) | 0x0000~0xFFFF | 0x00000000~ 0xFFFFFFFF | 0x00000000~ 0xFFFFFFFF | 0x0000000000000000~ 0xFFFFFFFFFFFFFFFF | 0x0000~0xFFFF | 0x00000000~ 0xFFFFFFFF | 0x00000000~ 0xFFFFFFFF | 0x0000000000000000~ 0xFFFFFFFFFFFFFFFF |
十六进制的两位,占据 1 Byte;
只有 unsigned 类型,十六进制的表示范围,和十进制的表示范围,是一一对应的;
实型
类型名称 | float(中文翻译:单精度) | double(中文翻译:双精度) | long double | bool |
所占字节数 | 4 Bytes | 8 Bytes | 16 Bytes | * 1(=8 Bits) Byte,见说明 |
表示范围 | -3.4E+38~3.4E+38 | -1.7E+308~1.7E+308 | -3.4E4932~3.4E4932 | true / false |
表示范围(十六进制) | 0x00000000~ 0xFFFFFFFF | 0x0000000000000000~ 0xFFFFFFFFFFFFFFFF | 0x0~ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
在C++中,bool 其实也是占一个字节(8 位)。这是比较特殊的地方。
字符型
类型名称 | char | unsigned char |
所占字节数 | 1 Byte | 1 Byte |
表示范围 | -128~127 | 0~255 |
表示范围(十六进制) | 0x00~ 0xFF | 0x00~ 0xFF |
2.3.4 语法 #
请运行下面的代码。
#include <iostream> using namespace std; int main() { float f(3.14); // 第一种写法 int a = (int)f; cout << "a = " << a << endl; // 第二种写法 int a = int(f); cout << "a = " << a << endl; return 0; }
以上的两种写法都可以。