zoukankan      html  css  js  c++  java
  • 从零开始给女朋友讲计算机 1 从比特、字节、补码到 ASCII、GB2312、Unicode

    起因

    在代码 review 的过程中,总是发现有人在数据类型转换(reinterpret_cast)、大小端等问题(什么情况下需要考虑大小端,什么情况下不需要考虑)上犯错误,究其原因是没有彻彻底底地搞懂数据的二进制表示。我想写篇文章,用通俗易懂的语言把这件事情说明白,通俗易懂到我的女朋友也能看懂。于是我就尝试着先做些铺垫,给她讲了些基础。发现效果出奇的好,于是赶紧把这一过程记录如下。

    0 和 1 的世界

    计算机的世界只有 0 和 1,所有的数据都由 0 和 1 的组合:数字、字母、汉字、图片、音乐、电影、游戏、网页等都可以由很多的 0 和 1 组成。

    计算机如何知道一长串的 0 和 1 是什么含义呢?

    比如 0100 0001 可能表示数字 65,可能表示大写字母A,可能和更多的 0 和 1 共同组成一个汉字,也可能表示图片上某个点的颜色,其意义完全取决于人们约定的规则

    比特和字节

    正着说:每一个 0 和 1 叫做一个比特(bit),8 个比特组成一个字节(Byte)。字节是计算机的基本单位,通常计算机一次最少处理一个字节。
    例如:人们常说的一个 Word 文档 100 KB,一张图片 2 MB,一首歌 10 MB,一部电影 4 GB,内存 8 GB,硬盘 512 GB 等等。这里的大“B”就是 Bytes,字节。
    比特(bit)最常见于宽带的宣传:例如 500M 宽带的完整单位是 500 Mbps(注意这里是小“b”,不是大“B”)。bps 即 bits per second,500Mbps 指的是每秒最大传输 500 兆比特(bit)。所以 500M 的宽带最快下载速度不是 500 MB/s,而是 500/8 = 62.5 MB/s。
    反着再说一次:一个字节(byte)有 8 个比特(bit);每个比特只能是 0 或 1,8 个比特一共有 2^8 = 256 种组合,可以代表 256 种含义(具体含义完全取决于人们约定的规则)。

    如何用 0 和 1 表示数字?

    假设现在我们想用一个字节表示数字,于是我们可以约定,8 个 bit 低位到高位每个 bit 分别具有不同的权重,分别代表 1,2,4,8,16,32,64,128。于是通过一个字节 8 个 bit 的各种组合,就能表示出 0 到 255 之间所有的数字了。

    高位 -> 低位 bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
    权重 128 64 32 16 8 4 2 1
    举例:0 0 0 0 0 0 0 0 0
    举例:1 0 0 0 0 0 0 0 1
    举例:35 0 0 1 0 0 0 1 1
    举例:65 0 1 0 0 0 0 0 1
    举例:128 1 0 0 0 0 0 0 0
    举例:255 1 1 1 1 1 1 1 1
    对于这种不考虑负数的情况,我们称之为无符号数

    那如何表示一个负数(有符号数)?

    有很多种方法,只要约定好一个规则即可。比如我们可以约定,最高位 bit7 代表符号位,0 代表正数,1 代表负数。于是一个字节,8 个 bit 可以表示 -127 到 127 的数字。注意其中 0 有两种表示,+0 和 -0。

    高位 -> 低位 bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
    权重 +/- 64 32 16 8 4 2 1
    举例:+0 0 0 0 0 0 0 0 0
    举例:-0 1 0 0 0 0 0 0 0
    举例:35 0 0 1 0 0 0 1 1
    举例:-65 1 1 0 0 0 0 0 1
    举例:127 0 1 1 1 1 1 1 1
    举例:-127 1 1 1 1 1 1 1 1

    现实计算机世界的负数几乎都是补码表示。和无符号数的规则相比,差别仅在最高位的权重为。于是一个字节,8 个 bit 可以表示 -128 到 127 的数字。其中 0 只有一种表示。

    高位 -> 低位 bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
    权重 -128 64 32 16 8 4 2 1
    举例:0 0 0 0 0 0 0 0 0
    举例:35 0 0 1 0 0 0 1 1
    举例:65 0 1 0 0 0 0 0 1
    举例:-128 1 0 0 0 0 0 0 0
    举例:127 0 1 1 1 1 1 1 1
    举例:-127 1 0 0 0 0 0 0 1
    举例:-1 1 1 1 1 1 1 1 1

    先停一下

    看到这里,如果问你,1000 0000 代表一个什么数字,你要怎么回答?千万别急着回答,回答之前应该先问清楚,要按照什么规则去解析。比如这串 0/1 表示的是一个无符号数还是一个补码表示的有符号数。

    如何表示更大的数?

    用多个字节表示。一个字节不够就两个,两个不够就四个、八个。用 2 个字节就能够表示 0 到 65535 之间的无符号数,用 4 个字节就能表示 0 到 4294967295 的无符号数!
    |高位 -> 低位| bit 15|bit 14 |bit 13 |bit 12 |bit 11 |bit 10 |bit 9| bit 8 | bit 7|bit 6|bit 5|bit 4|bit 3|bit 2|bit 1| bit 0|
    |-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|
    |权重|32768|16384|8192|4096|2048|1024|512|256|128|64|32|16|8|4|2|1|
    |举例:0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
    |举例:65|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|1|
    |举例:255|0|0|0|0|0|0|0|0|1|1|1|1|1|1|1|1|
    |举例:10000|0|0|1|0|0|1|1|1|0|0|0|1|0|0|0|0|
    |举例:40256|1|0|0|1|1|1|0|1|0|1|0|0|0|0|0|0|
    |举例:60666|1|1|1|0|1|1|0|0|1|1|1|1|1|0|1|0|

    有符号数(补码)也是类似的,只不过最高位的权重为负。用 2 个字节就能够表示 -32768 到 32767 之间的有符号数,用 4 个字节就能表示 -2147483648 到 2147483647 的有符号数!
    直接使用上面的表格(二进制表示的 bit 15 到 bit 0 和上面一模一样),但是现在按照补码的规则进行解析(即最高位权重为负),于是得到的结果就不一样了。
    |高位 -> 低位| bit 15|bit 14 |bit 13 |bit 12 |bit 11 |bit 10 |bit 9| bit 8 | bit 7|bit 6|bit 5|bit 4|bit 3|bit 2|bit 1| bit 0|
    |-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|
    |权重|-32768|16384|8192|4096|2048|1024|512|256|128|64|32|16|8|4|2|1|
    |举例:0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
    |举例:65|0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|1|
    |举例:255|0|0|0|0|0|0|0|0|1|1|1|1|1|1|1|1|
    |举例:-25280|1|0|0|1|1|1|0|1|0|1|0|0|0|0|0|0|
    |举例:-4870|1|1|1|0|1|1|0|0|1|1|1|1|1|0|1|0|

    十六进制:二进制的简化表示法

    二进制要用 8 个 0/1 表示一个 byte,太不方便,为简化表示,十六进制用分别用一个 0-F 表示一个字节的前 4 位和后 4 位。一般还会加上前缀0x,以提醒读者后面是 16 进制表示法。

    如何表示带小数点的浮点数?

    还是一样,只要约定好一个规则就行。计算机界流行的浮点数规则是 IEEE 定义单精度浮点(4 字节表示)和双精度浮点(8 字节表示)。浮点数的规则要稍微复杂一些,但也没什么特别难理解的。只是本文针对计算机初学者,不会涉及所有细节,后面可能会单独写一篇文章介绍浮点数的表示。

    如何表示字符?

    假设现在我们要用一个字节表示一个字符,我们可以约定,0000 0001 代表 a,0000 0002 代表 b,以此类推。从 0000 0000 到 1111 1111 的 256 种组合中表示 a-z、A-Z,加上各种标点符号也是绰绰有余。现实计算机世界几乎都心照不宣地采用 ASCII 规则来表示常见的英文字符、标点以及一些不显示的控制字符等。ASCII 只用了 7 个 bit,其中字符 a-z、A-Z、0-9 的表示在数值上都是连续的。选取部分例子如下:

    进制 十进制 十六进制 字符/缩写 解释
    00000000 0 0x00 NUL (NULL) 空字符
    00001010 10 0x0A LF/NL(Line Feed/New Line) 换行键
    00001101 13 0x0D CR (Carriage Return) 回车键
    00100000 32 0x20 (Space) 空格
    00100001 33 0x21 !
    00101100 44 0x2C ,
    00101110 46 0x2E .
    00110000 48 0x30 0
    00110001 49 0x31 1
    00110010 50 0x32 2
    01000000 64 0x40 @
    01000001 65 0x41 A
    01000010 66 0x42 B
    01000011 67 0x43 C
    01011000 88 0x58 X
    01011001 89 0x59 Y
    01011010 90 0x5A Z
    01100001 97 0x61 a
    01100010 98 0x62 b
    01100011 99 0x63 c
    01111000 120 0x78 x
    01111001 121 0x79 y
    01111010 122 0x7A z
    01111111 127 0x7F DEL (Delete) 删除

    如何表示汉字?

    一个字节一共就 256 种排列组合,就算每个组合代表一个汉字,也只能表示 256 个汉字,这显然是不够的。要想表示一个汉字,至少需要 2 个字节。这样就有 2^16 = 65536 种排列组合,可以表示 65536 个汉字了,应对常见的汉字已经不成问题。GB2312 编码就是用两个字节给汉字编码的。比如 0xB0A1 代表汉字“啊”,0xD7D3 代表汉字“子”。完整编码规则这里不详细展开。

    如何表示韩文、日文、阿拉伯文等所有字符?

    每个国家、地区都有自己的编码方式。比如同样的一串数字 1011 0000 1010 00010xB0A1 在 GB2312 编码下代表汉字“啊”,而在某种日文编码规则中则可能代表一个日文字符。如果一个日本程序员开发了一个软件,在日文编码的机器上可以正常显示日文,但是如果拿到中文编码的机器上就会显示乱码。为解决这一问题,推出了 Unicode 编码,为全世界的每一个字符都分配了一个独一无二的编码,甚至每个 emoji 表情都有自己的编码!现在只要所有的软件开发人员都统一采用 Unicode 编码方式,就再也不会出现乱码了。Unicode 采用 4 字节编码,可以表示 2^32 = 4294967295 个字符,足够容纳目前世界上所有已知的字符了。但是如果考虑到将这些字符信息保存下来,比如说保存到硬盘上,新的问题就来了:比如对于一个英文的纯文本文件,如何之前按 ASCII 编码,每个字符只要 1 个字节就够了,但是现在 Unicode 用 4 个字节编码,如果每个英文字符都用 4 个字节来存储(UTF-32),那么文件的大小将变成原来的 4 倍!为了解决这一问题,人们发明了 UTF-8。注意区分 UTF-8 和 Unicode:Unicode 是给每一个字符分配一个编号,从 0 到 4294967295;UTF-8 并不是给字符重新分配编号,每个字符的编号还是 Unicode 中定义、分配的编号,UTF-8 只是想方设法让 Unicode 在保存、传输的过程中减少所需的字节数的一种小技巧/规则,具体细节暂时不在这里展开,后期可能会专门写一篇文章介绍 UTF-8 是如何减少 Unicode 编码文件的体积。

    总结

    计算机的世界由 0/1 组成,数字、字母、图片等等所有信息都由一串串的 0/1 表示。8 个比特组成一个字节,字节是计算机的基本单位。一个字节可以表示 2^8 = 256 种含义,如何解析完全取决于人们约定的规则,要想知道字节的含义,必须要知道解析的规则(数据类型)。如果一个字节不足以表示所有的范围、可能性,就用多个字节表示。

  • 相关阅读:
    文件的上传&预览&下载学习(五)
    文件的上传&预览&下载学习(四)
    MySQL学习(一)大纲
    MySQL学习(四)锁机制
    MySQL学习(五)事务
    小程序在WXML页面添加的data属性,在点击事件中,获取的属性名皆为小写字母
    CSS解决数字,字母自动换行的问题添加wordbreak:breakall; wordwrap:breakword;
    理解CSS盒模型
    浮动
    对于第四章“流程控制”的学习和认识
  • 原文地址:https://www.cnblogs.com/tengzijian/p/14965165.html
Copyright © 2011-2022 走看看