重学计算机组成原理(十)- "烫烫烫"乱码的由来

程序 = 算法 + 数据结构

对应到计算机的组成原理(硬件层面)

  • 算法 --- 各种计算机指令
  • 数据结构 --- 二进制数据

计算机用0/1组成的二进制,来表示所有信息

  • 程序指令用到的机器码,是使用二进制表示的
  • 存储在内存里面的字符串、整数、浮点数也都是用二进制表示的

万物在计算机里都是0和1,搞清楚各种数据在二进制层面是怎么表示的,是我们的必修课。

在实际应用中最常遇到的问题,也就是文本字符串是怎么表示成二进制的,特别是我们会遇到的乱码究竟是怎么回事儿

在开发的时候,所说的Unicode和UTF-8之间有什么关系。

理解了这些,相信以后遇到任何乱码问题,你都能手到擒来了。

1 理解二进制的“逢二进一”

二进制和我们平时用的十进制,并没有本质区别,只是平时是“逢十进一”,这里变成了“逢二进一”

每一位,相比于十进制下的0~9这十个数字,我们只能用0和1这两个数字。

任何一个十进制的整数,都能通过二进制表示出来

把一个二进制数,对应到十进制,非常简单,就是把从右到左的第N位,乘上一个2的N次方,然后加起来,就变成了一个十进制数

当然,既然二进制是一个面向程序员的“语言”,这个从右到左的位置,自然是从0开始的。

比如_0011_这个二进制数,对应的十进制表示,就是

\(0×2^3+0×2^2+1×2^1+1×2^0\)
\(=3\)

代表十进制的3

对应地,如果我们想要把一个十进制的数,转化成二进制,使用短除法就可以了

也就是,把十进制数除以2的余数,作为最右边的一位。然后用商继续除以2,把对应的余数紧靠着刚才余数的右侧,这样递归迭代,直到商为0就可以了。

  • 比如,我们想把13这个十进制数,用短除法转化成二进制,需要经历以下几个步骤:

    因此,对应的二进制数,就是1101

刚才我们举的例子都是正数,对于负数来说,情况也是一样的吗?

我们可以把一个数最左侧的一位,当成是对应的正负号,比如0为正数,1为负数,这样来进行标记。

这样,一个4位的二进制数, 0011就表示为+3。而1011最左侧的第一位是1,所以它就表示-3。这个其实就是整数的原码表示法

原码表示法有一个很直观的缺点就是,0可以用两个不同的编码来表示,1000代表0, 0000也代表0。习惯万事一一对应的程序员看到这种情况,必然会被“逼死”。

于是,我们就有了另一种表示方法。我们仍然通过最左侧第一位的0和1,来判断这个数的正负。但是,我们不再把这一位当成单独的符号位,在剩下几位计算出的十进制前加上正负号,而是在计算整个二进制值的时候,在左侧最高位前面加个负号。

比如,一个4位的二进制补码数值1011,转换成十进制,就是

\(-1×2^3+0×2^2+1×2^1+1×2^0\)
\(=-5\)

如果最高位是1,这个数必然是负数;最高位是0,必然是正数。并且,只有0000表示0,1000在这样的情况下表示-8。一个4位的二进制数,可以表示从-8到7这16个整数,不会白白浪费一位。

当然更重要的一点是,用补码来表示负数,使得我们的整数相加变得很容易,不需要做任何特殊处理,只是把它当成普通的二进制相加,就能得到正确的结果。

我们简单一点,拿一个4位的整数来算一下,比如 -5 + 4 = -1,-5 + 6 = 1

我们各自把它们转换成二进制来看一看。如果它们和无符号的二进制整数的加法用的是同样的计算方式,这也就意味着它们是同样的电路。

2 字符串的表示,从编码到数字

不仅数值可以用二进制表示,字符乃至更多的信息都能用二进制表示

最典型的例子就是字符串(Character String)

最早计算机只需要使用英文字符,加上数字和一些特殊符号,然后用8位的二进制,就能表示我们日常需要的所有字符了,这个就是我们常常说的ASCII码(American Standard Code for Information Interchange,美国信息交换标准代码)

ASCII码就好比一个字典,用8位二进制中的128个不同的数,映射到128个不同的字符里

比如,小写字母a在ASCII里面,就是第97个,也就是二进制的0110 0001,对应的十六进制表示就是 61。而大写字母 A,就是第65个,也就是二进制的0100 0001,对应的十六进制表示就是41。

在ASCII码里面,数字9不再像整数表示法里一样,用0000 1001来表示,而是用0011 1001 来表示。字符串15也不是用0000 1111 这8位来表示,而是变成两个字符1和5连续放在一起,也就是 0011 0001 和 0011 0101,需要用两个8位来表示。

我们可以看到,最大的32位整数,就是2147483647。如果用整数表示法,只需要32位就能表示了。但是如果用字符串来表示,一共有10个字符,每个字符用8位的话,需要整整80位。比起整数表示法,要多占很多空间。

这也是为什么,很多时候我们在存储数据的时候,要采用二进制序列化这样的方式,而不是简单地把数据通过CSV或者JSON,这样的文本格式存储来进行序列化。不管是整数也好,浮点数也好,采用二进制序列化会比存储文本省下不少空间。

ASCII码只表示了128个字符,一开始倒也堪用,毕竟计算机是在美国发明的

然而随着越来越多的不同国家的人都用上了计算机,想要表示譬如中文这样的文字,128个字符显然是不太够用的。于是,计算机工程师们开始各显神通,给自己国家的语言创建了对应的字符集(Charset)和字符编码(Character Encoding)

字符集

表示的可以是字符的一个集合

比如“中文”就是一个字符集,不过这样描述一个字符集并不准确

想要更精确一点,我们可以说,“第一版《新华字典》里面出现的所有汉字”,这是一个字符集。这样,我们才能明确知道,一个字符在不在这个集合里面

比如,我们日常说的Unicode,其实就是一个字符集,包含了150种语言的14万个不同的字符。

字符编码

则是对于字符集里的这些字符,怎么一一用二进制表示出来的一个字典

我们上面说的Unicode,就可以用UTF-8、UTF-16,乃至UTF-32来进行编码,存储成二进制。所以,有了Unicode,其实我们可以用不止UTF-8一种编码形式,我们也可以自己发明一套 GT-32 编码,比如就叫作Geek Time 32好了。只要别人知道这套编码规则,就可以正常传输、显示这段代码。

同样的文本,采用不同的编码存储下来。如果另外一个程序,用一种不同的编码方式来进行解码和展示,就会出现乱码。这就好像两个军队用密语通信,如果用错了密码本,那看到的消息就会不知所云。在中文世界里,最典型的就是“手持两把锟斤拷,口中疾呼烫烫烫”的典故。

没有经验的同学,在看到程序输出“烫烫烫”的时候,以为是程序让CPU过热发出报警,于是尝试给CPU降频来解决问题。

既然今天要彻底搞清楚编码知识,我们就来弄清楚“锟斤拷”和“烫烫烫”的来龙去脉。

“锟斤拷”的来源

如果我们想要用Unicode编码记录一些文本,特别是一些遗留的老字符集内的文本,但是这些字符在Unicode中可能并不存在。于是,Unicode会统一把这些字符记录为U+FFFD这个编码

如果用UTF-8的格式存储下来,就是\xef\xbf\xbd。如果连续两个这样的字符放在一起,\xef\xbf\xbd\xef\xbf\xbd,这个时候,如果程序把这个字符,用GB2312的方式进行decode,就会变成“锟斤拷”。这就好比我们用GB2312这本密码本,去解密别人用UTF-8加密的信息,自然没办法读出有用的信息。

而“烫烫烫”,则是因为如果你用了Visual Studio的调试器,默认使用MBCS字符集

“烫”在里面是由0xCCCC来表示的,而0xCC又恰好是未初始化的内存的赋值。于是,在读到没有赋值的内存地址或者变量的时候,电脑就开始大叫“烫烫烫”了。

3 总结延伸

到这里,相信你发现,我们可以用二进制编码的方式,表示任意的信息。只要建立起字符集和字符编码,并且得到大家的认同,我们就可以在计算机里面表示这样的信息了。所以说,如果你有心,要发明一门自己的克林贡语并不是什么难事。

不过,光是明白怎么把数值和字符在逻辑层面用二进制表示是不够的。我们在计算机组成里面,关心的不只是数值和字符的逻辑表示,更要弄明白,在硬件层面,这些数值和我们一直提的晶体管和电路有什么关系。下一讲,我就会为你揭开神秘的面纱。我会从时钟和D触发器讲起,最终让你明白,计算机里的加法,是如何通过电路来实现的。

4 推荐阅读

  • 《编码:隐匿在计算机软硬件背后的语言》

    从电报机到计算机,这本书讲述了很多计算设备的历史故事,当然,也包含了二进制及其背后对应的电路原理。

参考

  • 深入浅出计算机组成原理

原文地址:https://www.cnblogs.com/JavaEdge/p/11373279.html

时间: 2024-11-10 07:57:56

重学计算机组成原理(十)- "烫烫烫"乱码的由来的相关文章

重学计算机组成原理(二)- 制定学习路线,攀登“性能”之巅

0 学习路线的知识点概括 学习计算机组成原理,就是学习计算机是如何协调运行的 计算机组成原理的英文叫Computer Organization Organization 意"组织机构". 该组织机构能够进行各种计算.控制.读取输入,进行输出,达成各种强大的功能. 把整个计算机组成原理的知识点拆分成了四大部分 计算机的基本组成 计算机的指令和计算 处理器设计 存储器和I/O设备. 0.1 计算机的基本组成 计算机的硬件组成 这些硬件,怎么对应到经典的冯·诺依曼体系结构的 除此之外,还需要

重学计算机组成原理(九)- 动态链接

把对应的不同文件内的代码段,合并到一起,成为最后的可执行文件 链接的方式,让我们在写代码的时候做到了"复用". 同样的功能代码只要写一次,然后提供给很多不同的程序进行链接就行了. "链接"其实有点儿像我们日常生活中的标准化.模块化生产. 有一个可以生产标准螺帽的生产线,就可生产很多不同的螺帽. 只要需要螺帽,都可以通过链接的方式,去复制一个出来,放到需要的地方 但是,如果我们有很多个程序都要通过装载器装载到内存里面,那里面链接好的同样的功能代码,也都需要再装载一遍,

重学计算机组成原理(六)- 函数调用怎么突然Stack Overflow了!

用Google搜异常信息,肯定都访问过Stack Overflow网站 全球最大的程序员问答网站,名字来自于一个常见的报错,就是栈溢出(stack overflow) 从函数调用开始,在计算机指令层面函数间的相互调用是怎么实现的,以及什么情况下会发生栈溢出 1 栈的意义 先看一个简单的C程序 function.c 直接在Linux中使用GCC编译运行 [[email protected] Documents]$ vim function.c [[email protected] Document

重学计算机组成原理(十一)- 门电路的"千里传音"

人用纸和笔来做运算,都是用十进制,直接用十进制和我们最熟悉的符号不是最简单么? 为什么计算机里我们最终要选择二进制呢? 来看看,计算机在硬件层面究竟是怎么表示二进制的,你就会明白,为什么计算机会选择二进制. 1 怎么做到"千里传书" 马拉松的故事相信你听说过.公元前490年,在雅典附近的马拉松海边,发生了波斯和希腊之间的希波战争.雅典和斯巴达领导的希腊联军胜利之后,雅典飞毛腿菲迪皮德斯跑了历史上第一个马拉松,回雅典报喜.这个时候,人们在远距离报信的时候,采用的是派人跑腿,传口信或者送信

【重学计算机】计组D1章:计算机系统概论

1.冯诺依曼计算机组成 主机(cpu+内存),外设(输入设备+输出设备+外存),总线(地址总线+数据总线+控制总线) 2.计算机层次结构 应用程序-高级语言-汇编语言-操作系统-指令集架构层-微代码层-硬件逻辑层 3.计算机性能指标 非时间指标 [字长]机器一次能处理的二进制位数 ,常见的有32位或64位 [总线宽度]数据总线一次能并行处理的最大信息位数,一般指运算器与存储器之间的数据总线的位数 [主存容量]主存的大小 [存储带宽]单位时间内与主存交换的二进制位数 B/s 时间指标 [主频f]时

【重学计算机】机组D8章:输入输出系统

1. 输入输出系统概述 组成:外设.接口.总线.管理软件 基本功能 完成计算机内外的信息传递 保证CPU正确选择输出设备 利用缓冲等,实现主机与外设的速度匹配 特点:异步性.实时性.设备无关性 输入过程:CPU把地址值放入总线 --> CPU等候设备数据有效 --> CPU从总线读入数据存入寄存器 输出过程:CPU把地址值放入总线 --> CPU把数据值放入总线 --> 设备等数据有效取走数据 IO系统性能:存储IO.通信IO 连接特性:哪些设备可以和IO相连 IO系统容量:IO系

【重学计算机】计组D3章:运算方法与运算器

1. 定点数运算及溢出 定点数加减法:减法化加法,用补码直接相加,忽略进位 溢出:运算结果超出了某种数据类型的表示范围 溢出检测方法:统一思想概括为正正得负或负负得正则溢出,正负或负正不可能溢出 方法1:V = XYS + XYS(XY为两个加数的符号位,S为结果的符号位,_表示非),那么V = 1则为溢出 方法2:V = C0 ⊕ C1(C0是最高数据位产生的进位,C1是符号位产生的进位),那么V = 1则为溢出 方法3:V = Xf1 ⊕ Xf2(数据采用变型补码 Xf1Xf2 X0X1X2

学计算机的值得一看的文章,跟帖也很有水平啊

转自http://blog.csdn.net/Xviewee/article/details/1606247 回复CSDN和KAOYAN诸位网友的几点看法,(为避免吵架,郑重声明,本人不是高手,只是有感而发的一点个人陋见,欢迎指正,事先感谢): 就我自己的理解,谈谈我对读研和软件学院的看法,不妥之处一笑了之即可. 如果你有实际开发工作经验,感觉自己的水平和实力进入了一个高原期,迫切需要从理论上提高,那么计算机学院是唯一选择.因为计算机学院才能让你在理论上更上一层楼.软件学院从教学计划上就没有

深入浅出计算机组成原理

课程目录:第00课.开篇词丨为什么你需要学习计算机组成原理?.rar第01课.冯-诺依曼体系结构:计算机组成的金字塔.rar第02课.给你一张知识地图,计算机组成原理应该这么学.rar第03课.通过你的CPU主频,我们来谈谈“性能”究竟是什么?.rar第04课.穿越功耗墙,我们该从哪些方面提升“性能”?.rar第05课.计算机指令:让我们试试用纸带编程.rar第06课.指令跳转:原来if.rar第07课.函数调用:为什么会发生stackoverflow?.rar第08课.ELF和静态链接:为什么