从零开始给女朋友讲计算机 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 个比特表示 0-255:人们约定,高位到低位每个 bit 有不同的权重,代表不同的值,如此便可用 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 |
举例: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 |
先停一下
看到这里,如果问你,1 0 0 0 0 0 0 0 代表一个什么数字,你要怎么回答?千万别急着回答,回答之前应该先问清楚,要按照什么规则去解析。比如这串 0/1 表示的是一个无符号数还是一个补码表示的有符号数。
如何表示更大的数?比如 10000
用多个字节表示。一个字节不够就两个,两个不够就三个、四个甚至八个十六个,直到够用!用 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。
进制 | 十进制 | 十六进制 | 字符/缩写 | 解释 |
---|---|---|---|---|
00000000 | 0 | 00 | NUL (NULL) | 空字符 |
00001010 | 10 | 0A | LF/NL(Line Feed/New Line) | 换行键 |
00001101 | 13 | 0D | CR (Carriage Return) | 回车键 |
00100000 | 32 | 20 | (Space) | 空格 |
00100001 | 33 | 21 | ! | |
00101100 | 44 | 2C | , | |
00101110 | 46 | 2E | . | |
00110000 | 48 | 30 | 0 | |
00110001 | 49 | 31 | 1 | |
00110010 | 50 | 32 | 2 | |
01000000 | 64 | 40 | @ | |
01000001 | 65 | 41 | A | |
01000010 | 66 | 42 | B | |
01000011 | 67 | 43 | C | |
01011000 | 88 | 58 | X | |
01011001 | 89 | 59 | Y | |
01011010 | 90 | 5A | Z | |
01100001 | 97 | 61 | a | |
01100010 | 98 | 62 | b | |
01100011 | 99 | 63 | c | |
01111000 | 120 | 78 | x | |
01111001 | 121 | 79 | y | |
01111010 | 122 | 7A | z | |
01111111 | 127 | 7F | DEL (Delete) | 删除 |
如何表示汉字?
一个字节一共就 256 种排列组合,就算每个组合代表一个汉字,也只能表示 256 个汉字,这显然是不够的。要想表示一个汉字,至少需要 2 个字节。这样就有 2^16 = 65536 种排列组合,可以表示 65536 个汉字了。应对常见的汉字已经不成问题。GB2312 编码就是用两个字节给汉字编码的。具体编码规则网上找得到,这里不详细展开。
如何表示韩文、日文、阿拉伯文等所有字符?
每个国家、地区都有自己的编码方式。比如同样的一串数字 1011 0000 1010 0001 在GB2312 编码下代表汉字“啊”,而在某种日文编码规则中则可能代表一个日文字符。
比如一个日本程序员开发了一个软件,在日文编码的机器上可以正常显示日文,但是如果拿到中文编码的机器上就会显示乱码。为解决这一问题,推出了 Unicode 编码。Unicode 采用 4 字节编码,可以表示 2^32 = 4294967295 个字符,足够容纳目前世界上所有已知的字符了,甚至包括各种 emoji 表情!
总结
计算机的世界由 0/1 组成,数字、字母、图片等等所有信息都由一串串的 0/1 表示。8 个比特组成一个字节,字节是计算机的基本单位。一个字节可以表示 2^8 = 256 种含义,如何解析完全取决于人们约定的规则。如果一个字节不足以表示所有的范围、可能性,就用多个字节表示。
从零开始给女朋友讲计算机 1 - 从比特、字节、补码到 ASCII、GB2312、Unicode的更多相关文章
- Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
计算机存储中有多少字节 题目 问题描述 在计算机存储中,12.5MB是多少字节? 答案提交 这是一道结果填空的题,你只需要算出结果后提交即可.本题的结果为一个整数,在提交答案时只填写这个整数,填写多余 ...
- 我给女朋友讲编程html系列(4) -- html常用简单标签
今天似乎有点感冒,浑身无力,在操场上躺了半个小时,好了许多.好了,废话不说了,还是写今天的教程吧. 1,html中的换行标签是 br,写法是: <br /> 2,html中有一些特殊的字符 ...
- 萌新web前端从零开始(1)——计算机入门
前言:这是一个萌新从零开始的学习之路,与大家分享自己的看法与见解,还请指出错误与遗漏点方便改正. 1.认识计算机. 计算机语言常见的有C,PHP,Ruby,Java,C#,Basic,JS,C++等, ...
- 我给女朋友讲编程总结建议篇,怎么学习html和css
总共写了11篇博客了,7篇讲html的,4篇讲网络的.不敢说写的多么好吧,最起码的是我迈出了写作的第一步,写作的过程中了解了一些其他的知识,比如SEO.几种重定向等,由于个人能力和见识有限,写出来的东 ...
- 我给女朋友讲编程html系列(3) --html中的超链接标签-a标签 和 框架frame与框架集frameset
我们浏览网页的时候,当单击某段文字或图片时,就会打开一个新的网页,这里面就使用了超链接. 就比如下图是一个导航类网页,当你单击某个链接就会打开新的网页. 比如,我拿我的qq空间“金河访谈”举例,新建一 ...
- 我给女朋友讲编程html系列(2) --Html标题标签h1
Html是一门标签语言,因此学习Html最快的方式就是学习使用html标签. html标题标签:h1,h2,h3,h4,h5,h6 标题标签总共有6个,h1,h2,h3,h4,h5,h6,从h1到h6 ...
- 我给女朋友讲编程html系列(1) -- Html快速入门
Html是一门编写网页的语言. 在我学习Html的时候,网上的很多朋友说,直接使用[记事本]编写就行了,最后保存为后缀名为 .html 的文件. 不过,我建议你用[Nodepad++]来编写网页,用这 ...
- 北京大学Cousera学习笔记--3-计算导论与C语言基础-第一讲.计算机的基本原理-计算机怎么计算-数的二进制
思考问题 1.“数”在计算机中是如何表示的? 2.逻辑上“数”是怎么运算的? 3.物理上“数”的计算是怎么实现的? 从图灵机计算问题得出: 1.字母表中的符号越多(几进制),读入移动次数减少,但程序数 ...
- 我给女朋友讲编程CSS系列(3) CSS如何设置字体的类型、大小、颜色,如何使用火狐浏览器的Firebug插件查看网页的字体
一.CSS如何设置字体的类型.大小.颜色 设计网页时,一般设置body的字体,让其他标签继承body的字体,这样设置特别方便,但是标题标签h1到h6和表单标签(input类型)是没有继承body的字体 ...
随机推荐
- [转]CAP和BASE理论
1. CAP理论 2000年7月,加州大学伯克利分校的Eric Brewer教授在ACM PODC会议上提出CAP猜想.2年后,麻省理工学院的Seth Gilbert和Nancy Lynch从理论上证 ...
- Lua学习高级篇
Lua学习高级篇 之前已经说了很多,我目前的观点还是那样,在嵌入式脚本中,Lua是最优秀.最高效的,如果您有不同的观点,欢迎指正并讨论,切勿吐槽.这个系列完全来自于<Programming in ...
- node.js学习(4)事件
1 导入事件库
- Python3.6 的字典为什么会快
作者:青南链接:https://zhuanlan.zhihu.com/p/73426505来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 在Python 3.5(含)以 ...
- 摄像头 ISP 调试的入门之谈(经验总结)
在讲述本文之前,我尽量以一个什么也不清楚的初学到入门的用词来阐述什么是 ISP 调试,以及为什么需要调试. 如果你从来都没有接触过什么是摄像头 ISP 调试,我想这个文章可以给你一些启发和关键词. 因 ...
- 视频动作定位的分层自关注网络:ICCV2019论文解析
视频动作定位的分层自关注网络:ICCV2019论文解析 Hierarchical Self-Attention Network for Action Localization in Videos 论文 ...
- Java 面试题关于包装类
这几个问题的知识点涉及的内容非常的刁钻,值得自己好好的理解. 问以下程序的输出结果是: 问题一: Object object=true ? new Integer(1):new Double(2.0) ...
- antd组件库BackTop组件设置动态背景图片的问题
有这么一个需求,利用antd组件库中的BackTop组件的逻辑,但是自己写样式. 我的目标样式是:有两张图片,一张是normal(正常情况),一张是hover(悬停情况). 这时候就要用到css的动画 ...
- Kubernetes 实战——配置应用(ConfigMap、Secret)
配置容器化应用的方式:①命令行参数:②环境变量:③文件化配置 一.向容器传递命令行参数或环境变量 这两种方式在 Pod 创建后不可被修改 1. 在Docker中定义命令与参数 ENTRYPOINT:容 ...
- python operator操作符函数
本模块主要包括一些Python内部操作符对应的函数.这些函数主要分为几类:对象比较.逻辑比较.算术运算和序列操作.