字符编码那些事(C语言版)

前言

你是否遇到过这种情况:

#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个过程:

  1. 输入数据
  2. 处理数据
  3. 输出数据

由于计算机唯一能识别并执行的编程语言是机器语言,这3个过程可以看作:

  1. 输入二进制编码
  2. 处理二进制编码
  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

小结

综合上述,我们可以整理出以下概念:

字符集:
需要编码成二进制的字符组成的集合

字符编码方案:
把特定字符集中的字符编码成二进制的方案

字符编码:
字符编码有两个含义:

  • 指按照特定字符编码方案把字符编码成二进制的过程
  • 指按照特定字符编码方案把字符编码成二进制所得到二进制编码,也叫字集码

字符解码:
按照特定字符编码方案把二进制编码解码成字符的过程

以上概念有几点需要注意:

  1. 字符编码方案基于字符集
  2. 当提到字符编码时,一般只会提字符编码方案,因为字符集字符编码方案是一对多的关系,通过唯一的字符编码方案能够确定唯一的字符集,但通过唯一的字符集不能确定唯一的字符编码方案
  3. 一种字符编码方案应该保证:字符集中不同的字符按照此方案编码后得到的二进制编码不相同

常见的字符集与字符编码方案

下面介绍几种常见的字符编码方案。

标准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
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值