2019-11-12

深入浅出计算机编码

什么是编码

编码的本质就是让只认识 0 和 1 的计算机,能够理解我们人类使用的语言符号,并且将数据转换为二进制进行存储和传输。

为什么计算机只认识 0 和 1

电子计算机主要是采用数字集成电路搭建的,数字集成电路的基本单元是逻辑门,通过控制高电平和低电平(相当于 1 和 0),从而实现逻辑运算。

什么是二进制

二进制是计算技术中广泛采用的一种数制。二进制数据是用 0 和 1 两个数码来表示的数。

为什么将数据转换为二进制进行存储和传输

因为数字计算机是由逻辑门组成,而逻辑电路最基础的状态就是两个「开」和「关」。所以,数字电路是以二进制逻辑代数为数学基础。二进制的基本运算规则简单,运算操作方便,这样一来有利于简化计算机内部结构,提高运算速度。而且在逻辑代数方面,二进制只有 0 和 1 两个数码,正好与逻辑代数中的「真」和「假」相吻合。

什么是编码表

人类语言到计算机语言转换的形式,就叫做编码表,它让人类语言和计算机语言能够一一对应起来。
常用的编码表如下所示:

编码表 适用性 特点
ASCII 码 英文大小写,字符,不支持中文 最早的编码,占用空间小
GB2312 码、GBK 码 支持了中文 GBK 是 GB2312 的升级
Unicode 码 支持国际语言 占用空间大,适用性强
UTF-8 码 支持国际语言 Unicode 码升级版,两者之间容易转换。ASCII 码被 UTF-8 码包含

什么是位

位的英文名是 bit,是电子计算机中最小的数据单位,每一个位(bit)的状态只能是 0 或 1。

位、二进制、十六进制的关系

位与二进制:

  • 1 位(bit)= 1 个二进制位
  • 1 字节(Byte) = 8 位(bit)
  • 1 字节(Byte) = 8 个二进制位
  • 8 个二进制位 = 00000000 - 11111111 = 十进制位 0 ~ 255

位、二进制与十六进制

  • 1 个十六进制位 = 0 ~ F = 0 ~ 15
  • 4 个二进制位 = 0000 ~ 1111 = 0 ~ 15
  • 4 个二进制位 = 1 个十六进制位
  • 1 个字节(Byte)= 8 位(bit)= 8 个二进制位 = 2 个十六进制位 = 0 ~ 255

二进制位与十进制位相互转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 二进制位转换成为十进制位
00000001 = (0 x 128) + (0 x 64) + (0 x 32) + (0 x 16) + (0 x 8) + (0 x 4) + (0 x 2) + (1 x 1) = 1
10000111 = (1 x 128) + (0 x 64) + (0 x 32) + (0 x 16) + (0 x 8) + (1 x 4) + (1 x 2) + (1 x 1) = 135

# 十进制位与二进制位相互转换
135 / 2 = 67(余数为 1)
67 / 2 = 33(余数为 1)
33 / 2 = 16(余数为 1)
16 / 2 = 8 (余数为 0)
8 / 2 = 4 (余数为 0)
4 / 2 = 2 (余数为 0)
2 / 2 = 1 (余数为 0)
1 / 2 = 0 (余数为 1)

10000111

十六进制与十进制互相转换

1
2
3
4
5
6
# 十六进制转换成十进制:2AF5
5 * 16^0 = 5
F * 16^1 = 240
A * 16^2 = 2560
2 * 16^3 = 8192
5 * 16^0 + F * 16^1 + A * 16^2 + 2 * 16^3 = 10997

二进制与编码表

世界上存在多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。ASCII 编码表只规定了 128 个字符,仅仅表示中文就不够用了。伴随互联网的普及,强烈要求出现一种统一的编码方式。UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。

UTF-8 编码规则

Unicode 是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码如何存储。UTF-8 是 Unicode 的实现方式之一。是一种可变的编码方式,可以使用 1 ~ 4 个字节表示一个字符。

  • 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
  • 对于 n 字节的符号(n > 1),第一个字节的前 n 位都设为 1,第 n + 1 位设为 0,后面字节的前两位一律设为 10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
Unicode 符号范围 UTF-8 编码方式
十六进制 二进制
0000 0000-0000 007F 0xxxxxxx
0000 0080-0000 07FF 110xxxxx 10xxxxxx
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

字为例,的 Unicode 是 5362,转换成为二进制是 101 0011 0110 0010,根据上表,5362 处于第三行范围内(0000 0800-0000 FFFF),然后,从的最后一个二进制位开始,依次从后向前填入格式中的 x,多出的位补 0。这样就得到了,的 UTF-8 编码是11100101 10001101 10100010,转换成十六进制就是 E58DA2。运算过程如下:

1
2
3
4
5
6
7
8
9
10
11
# UTF-8 编码出现的二进制位
1110xxxx 10xxxxxx 10xxxxxx
101 001101 100010
11100101 10001101 10100010

# 二进制位转十六进制位
11100101 10001101 10100010 = E58DA2

# 存储单位
11100101 10001101 10100010 = 24 个二进制位 = 3 个字节
E58DA2 = 6 个十六进制位 = 3 个字节

新建一个文件,然后往里写入汉字,保存之后退出查看文件大小,执行命令如下:

1
2
3
4
5
6
7
8
9
10
11
# 创建文件
touch test

# 用 vscode 打开并写入汉字「卢」
code test

# 查看文件大小
ls -lht

# 显示文件 3B,三个字节
-rw-r--r-- 1 sebastian staff 3B 12 6 14:14 test