跳至正文
View Categories

5 min read

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 整型 #

类型名称shortintlonglong longunsigned shortunsigned intunsigned longunsigned long long
所占字节数2 Bytes4 Bytes4 Bytes8 Bytes2 Bytes4 Bytes4 Bytes8 Bytes
表示范围-32768~32767-2147483648~ 2147483647-2147483648~ 2147483647-9223372036854775808~ 92233720368547758070~655350~ 42949672950~ 42949672950~ 18446744073709551615
表示范围(十六进制)0x0000~0xFFFF0x00000000~ 0xFFFFFFFF0x00000000~ 0xFFFFFFFF0x0000000000000000~ 0xFFFFFFFFFFFFFFFF0x0000~0xFFFF0x00000000~ 0xFFFFFFFF0x00000000~ 0xFFFFFFFF0x0000000000000000~ 0xFFFFFFFFFFFFFFFF
  • 十六进制的两位,占据 1 Byte;
  • 只有 unsigned 类型,十六进制的表示范围,和十进制的表示范围,是一一对应的;

1.6.2 实型 #

类型名称float(中文翻译:单精度)double(中文翻译:双精度)long doublebool
所占字节数4 Bytes8 Bytes16 Bytes* 1(=8 Bits) Byte,见说明
表示范围-3.4E+38~3.4E+38-1.7E+308~1.7E+308-3.4E4932~3.4E4932true / false
表示范围(十六进制)0x00000000~ 0xFFFFFFFF0x0000000000000000~ 0xFFFFFFFFFFFFFFFF0x0~ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

在C++中,bool 其实也是占一个字节(8 位)。这是比较特殊的地方。

1.6.3 字符型 #

  • 字符型还未介绍,将在后续章节讲解。
类型名称charunsigned char
所占字节数1 Byte1 Byte
表示范围-128~1270~255
表示范围(十六进制)0x00~ 0xFF0x00~ 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 的操作系统为例说明:

整型

类型名称shortintlonglong longunsigned shortunsigned intunsigned longunsigned long long
所占字节数2 Bytes4 Bytes4 Bytes8 Bytes2 Bytes4 Bytes4 Bytes8 Bytes
表示范围-32768~32767-2147483648~ 2147483647-2147483648~ 2147483647-9223372036854775808~ 92233720368547758070~655350~ 42949672950~ 42949672950~ 18446744073709551615
表示范围(十六进制)0x0000~0xFFFF0x00000000~ 0xFFFFFFFF0x00000000~ 0xFFFFFFFF0x0000000000000000~ 0xFFFFFFFFFFFFFFFF0x0000~0xFFFF0x00000000~ 0xFFFFFFFF0x00000000~ 0xFFFFFFFF0x0000000000000000~ 0xFFFFFFFFFFFFFFFF

十六进制的两位,占据 1 Byte;
只有 unsigned 类型,十六进制的表示范围,和十进制的表示范围,是一一对应的;

实型

类型名称float(中文翻译:单精度)double(中文翻译:双精度)long doublebool
所占字节数4 Bytes8 Bytes16 Bytes* 1(=8 Bits) Byte,见说明
表示范围-3.4E+38~3.4E+38-1.7E+308~1.7E+308-3.4E4932~3.4E4932true / false
表示范围(十六进制)0x00000000~ 0xFFFFFFFF0x0000000000000000~ 0xFFFFFFFFFFFFFFFF0x0~ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

在C++中,bool 其实也是占一个字节(8 位)。这是比较特殊的地方。

字符型

类型名称charunsigned char
所占字节数1 Byte1 Byte
表示范围-128~1270~255
表示范围(十六进制)0x00~ 0xFF0x00~ 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;
}

以上的两种写法都可以。