文章目录
前言
你是否遇到过这种情况:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf("Hello, world!\n"); //鎴戠殑绗竴涓▼搴
printf("鎴戞槸灏忔槑\n");
system("pause");
return 0;
}
或这种:
Hello, world!
浣犲ソ锛屼笘鐣岋紒
还有这种:
abcdef烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫
以及这种:
123456屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯
其实,造成以上几种情况的罪魁祸首都是 —— 字符编码。
机器处理的数据由 0 和 1 组成
相信大家对计算机世界中的 0 和 1 已经非常熟悉了。没错,计算机的世界其实就是 0 和 1 的世界。
作为程序员,尽管我们可以用各种各样的高级语言来编写我们的程序,但殊途同归的是,我们的程序在被计算机执行前,都会被转换成机器指令码,存放到二进制文件中。
机器指令码:
也叫机器语言
,是计算机能够理解并执行的指令。机器指令码用二进制编码
表示。
二进制编码:
0 和 1 的序列
机器语言:
计算机唯一能识别并执行的编程语言
二进制文件:
用于存储机器指令码的文件
当我们编写一个程序来解决一类问题时,从计算机的角度来看,程序的执行经历了3个过程:
- 输入数据
- 处理数据
- 输出数据
由于计算机唯一能识别并执行的编程语言是机器语言
,这3个过程可以看作:
- 输入二进制编码
- 处理二进制编码
- 输出二进制编码
这就是今天的主角 —— 字符编码
产生的背景。
由文字到二进制编码
既然机器处理的数据都是由 0 和 1 组成的,那么……
老师:
问题来了,如果计算机只认识 0 和 1,想要让计算机帮忙处理文字怎么办?
甲同学:
重新买一台认识文字的计算机
乙同学:
那还不简单?把文字转换成 0 和 1 不就行了吗?
丙同学:
可以用二进制数表示文字,一个二进制数对应一个字,比如:
‘我’ 对应 0,
‘你’ 对应 1,
‘他’ 对应 10,
‘他们’ 对应11
以此类推
老师:…
丙同学提出的办法看起来十分不错:
0 → 我
1 → 你
10 → 他
11 → 他们
…
让我们试着完善一下丙同学的方案:
<1> 假设计算机需要处理的文字仅包括:
- 26个小写英文字母
- 26个大写英文字母
- 英文逗号
,
- 英文句点
.
- 英文感叹号
!
<2> 我们把由计算机需要处理的文字组成的集合称为
字符集
,暂且把这 55 个文字组成的字符集取名为Mini
字符集
<3> 确定了字符集,我们现在唯一要做的就是确定一种方案,把字符集中的文字与二进制数一一对应起来。这种把
字符集
中的字符映射为二进制编码的方案称为字符编码方案
,映射得到的二进制编码称为字符编码
<4> 我们采取最简单而直观的一种方案 —— 从 0 开始按照一定的顺序给字符集中的文字编号,然后把编号的二进制形式作为字符编码
1. 首先,把 Mini 字符集中的文字按照 <a-z、A-Z、逗号、句号、感叹号> 的顺序排好序 2. 把字母 a 的编号设为 0,从 a 到 ! 编号递增,感叹号 ! 的编号是 54 3. 如此,字母 a 的字符编码是 0,感叹号 ! 的字符编码是 110110
<5> 我们把这种字符编码方案命名为
Mini-Simple
编码方案
到现在为止,我们确定了 Mini
字符集,还确定基于 Mini 字符集的一种字符编码方案 —— Mini-Simple
编码方案
按照 Mini-Simple 字符编码方案,如果想让计算机逆序输出 Hello,world!
这句话,那么程序输入输出的二进制数据应该是:
输入(文字):
Hello,world!
输入(编号):33 4 11 11 14 52 22 14 17 11 3 54
输入(字符编码):100001 100 1011 1011 1110 110100 10110 1110 10001 1011 11 110110
输出(字符编码):110110 11 1011 10001 1110 10110 110100 1110 1011 1011 100 100001
输出(编号):54 3 11 17 14 22 52 14 11 11 4 33
输出(文字):
!dlrow,olleH
小结
综合上述,我们可以整理出以下概念:
字符集:
需要编码成二进制
的字符组成的集合
字符编码方案:
把特定字符集
中的字符编码成二进制的方案
字符编码:
字符编码有两个含义:
- 指按照特定
字符编码方案
把字符编码成二进制的过程- 指按照特定
字符编码方案
把字符编码成二进制所得到二进制编码,也叫字集码
字符解码:
按照特定字符编码方案
把二进制编码解码成字符的过程
以上概念有几点需要注意:
字符编码方案
基于字符集
- 当提到字符编码时,一般只会提字符编码方案,因为
字符集
和字符编码方案
是一对多的关系,通过唯一的字符编码方案
能够确定唯一的字符集
,但通过唯一的字符集
不能确定唯一的字符编码方案
- 一种字符编码方案应该保证:字符集中不同的字符按照此方案编码后得到的二进制编码不相同
常见的字符集与字符编码方案
下面介绍几种常见的字符编码方案。
标准ASCII
ASCII((American Standard Code for Information Interchange): 美国信息交换标准代码)是基于拉丁字母的一种字符编码方案,主要用于编码英语和西欧语言。
标准 ASCII 是最通用的字符编码方案,等同于国际标准 ISO/IEC 646。
标准 ASCII 基于由128个字符构成的字符集,字符集中的字符由 ASCII 标准规定,包括:
- 控制字符
- 通信专用字符
- 空格
- 阿拉伯数字
- 大小写英文字母
- 标点符号
- 运算符号
标准 ASCII 的编码方式类似于 Mini-Simple 字符编码方案,采取 字符——编号——编码
的方式。
ASCII 标准中规定,用标准 ASCII 编码的字符的字符编码用 7 位二进制数的组合表示。在使用标准 ASCII 时,会在字符编码的最高位补0使之成为一个字节(一个字节通常是 8 位二进制)。
以下是标准 ASCII 码表:
Bin(二进制) | Oct(八进制) | Dec(十进制) | Hex(十六进制) | 缩写/字符 | 解释 |
---|---|---|---|---|---|
0000 0000 | 00 | 0 | 0x00 | NUL(null) | 空字符 |
0000 0001 | 01 | 1 | 0x01 | SOH(start of headline) | 标题开始 |
0000 0010 | 02 | 2 | 0x02 | STX (start of text) | 正文开始 |
0000 0011 | 03 | 3 | 0x03 | ETX (end of text) | 正文结束 |
0000 0100 | 04 | 4 | 0x04 | EOT (end of transmission) | 传输结束 |
0000 0101 | 05 | 5 | 0x05 | ENQ (enquiry) | 请求 |
0000 0110 | 06 | 6 | 0x06 | ACK (acknowledge) | 收到通知 |
0000 0111 | 07 | 7 | 0x07 | BEL (bell) | 响铃 |
0000 1000 | 010 | 8 | 0x08 | BS (backspace) | 退格 |
0000 1001 | 011 | 9 | 0x09 | HT (horizontal tab) | 水平制表符 |
0000 1010 | 012 | 10 | 0x0A | LF (NL line feed, new line) | 换行键 |
0000 1011 | 013 | 11 | 0x0B | VT (vertical tab) | 垂直制表符 |
0000 1100 | 014 | 12 | 0x0C | FF (NP form feed, new page) | 换页键 |
0000 1101 | 015 | 13 | 0x0D | CR (carriage return) | 回车键 |
0000 1110 | 016 | 14 | 0x0E | SO (shift out) | 不用切换 |
0000 1111 | 017 | 15 | 0x0F | SI (shift in) | 启用切换 |
0001 0000 | 020 | 16 | 0x10 | DLE (data link escape) | 数据链路转义 |
0001 0001 | 021 | 17 | 0x11 | DC1 (device control 1) | 设备控制1 |
0001 0010 | 022 | 18 | 0x12 | DC2 (device control 2) | 设备控制2 |
0001 0011 | 023 | 19 | 0x13 | DC3 (device control 3) | 设备控制3 |
0001 0100 | 024 | 20 | 0x14 | DC4 (device control 4) | 设备控制4 |
0001 0101 | 025 | 21 | 0x15 | NAK (negative acknowledge) | 拒绝接收 |
0001 0110 | 026 | 22 | 0x16 | SYN (synchronous idle) | 同步空闲 |
0001 0111 | 027 | 23 | 0x17 | ETB (end of trans. block) | 结束传输块 |
0001 1000 | 030 | 24 | 0x18 | CAN (cancel) | 取消 |
0001 1001 | 031 | 25 | 0x19 | EM (end of medium) | 媒介结束 |
0001 1010 | 032 | 26 | 0x1A | SUB (substitute) | 代替 |
0001 1011 | 033 | 27 | 0x1B | ESC (escape) | 换码(溢出) |
0001 1100 | 034 | 28 | 0x1C | FS (file separator) | 文件分隔符 |
0001 1101 | 035 | 29 | 0x1D | GS (group separator) | 分组符 |
0001 1110 | 036 | 30 | 0x1E | RS (record separator) | 记录分隔符 |
0001 1111 | 037 | 31 | 0x1F | US (unit separator) | 单元分隔符 |
0010 0000 | 040 | 32 | 0x20 | (space) | 空格 |
0010 0001 | 041 | 33 | 0x21 | ! | 叹号 |
0010 0010 | 042 | 34 | 0x22 | " | 双引号 |
0010 0011 | 043 | 35 | 0x23 | # | 井号 |
0010 0100 | 044 | 36 | 0x24 | $ | 美元符 |
0010 0101 | 045 | 37 | 0x25 | % | 百分号 |
0010 0110 | 046 | 38 | 0x26 | & | 和号 |
0010 0111 | 047 | 39 | 0x27 | ’ | 闭单引号 |
0010 1000 | 050 | 40 | 0x28 | ( | 开括号 |
0010 1001 | 051 | 41 | 0x29 | ) | 闭括号 |
0010 1010 | 052 | 42 | 0x2A | * | 星号 |
0010 1011 | 053 | 43 | 0x2B | + | 加号 |
0010 1100 | 054 | 44 | 0x2C | , | 逗号 |
0010 1101 | 055 | 45 | 0x2D | - | 减号/破折号 |
0010 1110 | 056 | 46 | 0x2E | . | 句号 |
0010 1111 | 057 | 47 | 0x2F | / | 斜杠 |
0011 0000 | 060 | 48 | 0x30 | 0 | 字符0 |
0011 0001 | 061 | 49 | 0x31 | 1 | 字符1 |
0011 0010 | 062 | 50 | 0x32 | 2 | 字符2 |
0011 0011 | 063 | 51 | 0x33 | 3 | 字符3 |
0011 0100 | 064 | 52 | 0x34 | 4 | 字符4 |
0011 0101 | 065 | 53 | 0x35 | 5 | 字符5 |
0011 0110 | 066 | 54 | 0x36 | 6 | 字符6 |
0011 0111 | 067 | 55 | 0x37 | 7 | 字符7 |
0011 1000 | 070 | 56 | 0x38 | 8 | 字符8 |
0011 1001 | 071 | 57 | 0x39 | 9 | 字符9 |
0011 1010 | 072 | 58 | 0x3A | : | 冒号 |
0011 1011 | 073 | 59 | 0x3B | ; | 分号 |
0011 1100 | 074 | 60 | 0x3C | < | 小于 |
0011 1101 | 075 | 61 | 0x3D | = | 等号 |
0011 1110 | 076 | 62 | 0x3E | > | 大于 |
0011 1111 | 077 | 63 | 0x3F | ? | 问号 |
0100 0000 | 0100 | 64 | 0x40 | @ | 电子邮件符号 |
0100 0001 | 0101 | 65 | 0x41 | A | 大写字母A |
0100 0010 | 0102 | 66 | 0x42 | B | 大写字母B |
0100 0011 | 0103 | 67 | 0x43 | C | 大写字母C |
0100 0100 | 0104 | 68 | 0x |