《操作系统真象还原》——0.27 转义字符与ASCII码

简介: 计算机世界中是以二进制来运行的,无论是指令、数据,都是以二进制的形式提交给硬件处理的,字符也一样,必须转换成二进制才能被计算机识别。所以各种各样的字符编码产生,简单来说,字符编码就是用唯一的一个二进制串表示唯一的一个字符。

本节书摘来自异步社区《操作系统真象还原》一书中的第0章,第0.27节,作者:郑钢著,更多章节内容可以访问云栖社区“异步社区”公众号查看

0.27 转义字符与ASCII码

计算机世界中是以二进制来运行的,无论是指令、数据,都是以二进制的形式提交给硬件处理的,字符也一样,必须转换成二进制才能被计算机识别。所以各种各样的字符编码产生,简单来说,字符编码就是用唯一的一个二进制串表示唯一的一个字符。其中最著名的字符编码就是ASCII码。

ASCII码表中字符按可见分成两大类,一类是不可见字符,共33个,它们的ASCII码值是0~31和127,属于控制字符或通信专用字符。表中其余的字符是可见字符,它们的ASCII码值是32~126,属于数字、字母、各种符号。

对于计算机来说,任何字符都是用ASCII码表示的,人要是与计算机交流,虽然可以直接输入字符的ASCII码,但这太不人道了,计算机的发明是为了给人解决问题而并非制造问题。人习惯用所见即所得的方式使用字符,我要输入字符a的时候,直接按下键盘上的a键就行了,不要让我输入其ASCII码0x61。这要求是合理的,我们在键盘上键入的每个按键,都会由输入系统根据ASCII码表转换成对应的二进制ACSII码形式。这对普通用户来说够用了,他们很少写程序,可是作为程序员,我们经常要输出字符串,字符串中的可见字符直接从键盘敲入就行了,对于那些不可见字符,如回车换行符等,肯定不能用键盘在字符串中直接敲下一个回车键。

我们的问题是不可见字符如何写出来,也就是说我们在写字符串时,如何在其中加入不可见的控制符,这就需要编译器或解释器的支持了。

由于可见字符本身是看得见的,所见即所得,大家在使用中并不会有陌生感。对于那些不可见的控制字符,如果想使用它们时,该怎样表示它们呢?比如我就是要让程序输出一段话,在结束处换行。控制字符看不见摸不着,怎么写出来?所以在使用这些不可见字符时必须想办法让其可见,但又不能表示成其他可见字符,所以,只能让可见字符不表示自身了,哈哈,有点难是吗?这么艰巨的任务显然只用一个可见字符是不可能完成的,于是编译器想出了一个办法,它引用了另一个可见字符''来搭配其他可见字符,用这种可见字符组合的形式表达不可见字符。表面上看,字符''是让其他可见字符的意义变了,所以称''为转义字符,但本质上,这两个可见字符合起来才是完整的不可见字符,比如换行符'n',''和'n'放到一起才是换行符的意义,并不是因为'n'前面有个'','n'就不再是'n',而是换行符,一定要清楚不是这样的。

ASCII码表中任何字符都是1个字节大小,在字符串中不可见字符虽然用“转义字符+可见字符”两个字符来表示,但这只是编译器为了让人们能写出不可见字符的方式,目的是让不可见字符变得“可见”,针对的是人,这样人们写程序时就能在字符串中用到不可见字符。不可见字符本身在编译后还是那1个字节的ASCII码。说白了,我们能够将不可见字符显示出来,原因就是编译器在给我们做支持,它将“转义字符+可见字符”这种形式的不可见字符转换成了该不可见字符的ASCII码。

为了说清楚,咱们以编译器为界限,在编译器左边的是人,这里的字符串是供人使用的,转义字符是存在于这一边的。编译器右边的是机器,这里的字符串使用的都是ASCII码。

在编译器左边:

char* ptr=”abc\n”;
此部分对应的内容是0x61 0x62 0x63 0x5c 0x6e。

编译器右边:

“abcn”对应的内容是0x61 0x62 0x63 0xa

编译器的左边和右边是不一样的,区别是对“n”的处理。编译器左边把它当成了两个字符,编译器右边把它当成了一个字符。想想也是,毕竟代码只是文本字符串,字符串”abcn”中的''和'n'肯定是两个字符,编译器会把''和'n'组合到一起成为'n'而解释成回车换行。可能您还是觉得怀疑,那我说一下编译器对字符串的解释过程。

编译器对字符串的处理一般是逐个字符处理的,这样便于处理转义字符。若发现字符为'',就意识到这是转义字符,按常理说后面肯定要跟着另一可见字符,于是先不做任何处理,马上把后面的字符读进来,分析这两个字符的组合是哪个控制字符后一并处理。

咱们这里拿编译器解释字符串”abcn”举例。

代码中的'n'本身由两个字符''和'n'组成,'n'是给人看的,用于在字符串中使用,其ASCII码是0xa,是给机器看的。在计算机中,所有的字符都已经成了ASCII码,字符串”abcn”则变成了ASCII码:0x61 0x62 0x63 0x5c 0x6e。

编译器要逐个对比字符串中每个字符,前几个字符是'a'、'b'、'c',这都是可见字符,没有异议,直接处理。当发现字符是'',知道这是转义字符,得知道''后面的字符是什么才能确定是哪个不可见字符,于是暂停处理'',把后面的字符读进来,发现是'n',便知道这是'n',表示一个换行符,于是将''和'n'用换行符的ASCII代替,原来字符串”abcn”的ASCII码就变成了0x61 0x62 0x63 0xa。

说得足够多了,我也嫌自己啰嗦了,大家看以下的例子吧,就在图0-20中全部解释清楚了。

代码ASCII.c过于简单,纯粹是为演示。大家可能注意到了xxd.sh这个脚本,它就是xxd命令的封装,xxd命令可以逐字节查看文件,xxd.sh脚本内容如下。

#usage: sh xxd.sh 文件起始地址长度
xxd -u -a -g 1 -s $2 -l $3 $1
#以下为参数解释。
#-u  use upper case hex letters. Default is lower case.
#
#-a | -autoskip
#          toggle autoskip: A single '*' replaces nul-lines.  Default off.
#
#-g bytes | -groupsize bytes
#       separate the output of every <bytes> bytes (two hex characters or eight bit-digits each) by a whitespace.  Specify -g 0 to
#      suppress grouping.  <Bytes> defaults to 2 in normal mode and 1 in bits mode.  Grouping does not  apply  to  postscript  or
#      include style.
#
#-c cols | -cols cols
#                    format <cols> octets per line. Default 16 (-i: 12, -ps: 30, -b: 6). Max 256.
#
#-s [+][-]seek
#     start at <seek> bytes abs. (or rel.) infile offset.  + indicates that the seek is relative to the current stdin file position
#     (meaningless when not reading from stdin).  - indicates that the seek should be that many characters from the end of
#     the input (or if combined with +: before the current stdin file position).
#     Without -s option, xxd starts at  the  current file position.

screenshot

希望对大家理解转义字符有帮助。

相关文章
|
存储 小程序 Unix
《操作系统真象还原》——0.28 MBR、EBR、DBR和OBR各是什么
MBR和EBR是分区工具创建维护的,不属于操作系统管理的范围,因此操作系统不可以往里面写东西,注意这里所说的是“不可以”,其实操作系统是有能力读写任何地址的,只是如果这样做的话会破坏“系统控制权接力赛”所使用的数据,下次开机后就无法启动了。
3427 0
|
Linux C语言
《操作系统真象还原》——导读
以上情况对我们学习操作系统来说也同样存在,比如当老师介绍中断发生时的上下文保护时,我们更多的疑问不是如何保存CPU的上下文数据,而是想知道为什么在不同的特权级下会使用不同的栈,这背后的原理是什么,并且这是如何做到的。
1614 0
|
JavaScript 前端开发 Linux
《操作系统真象还原》——2.3 让MBR先飞一会儿
虽说主引导记录mbr是咱们能够掌控的第一个程序,但这并不是让我们为之激动的理由。我们平时所写的程序都要依赖于操作系统,而我们即将实现的这个程序是独立于操作系统的,能够直接在裸机上运行,这才是让我们激动的理由,对咱们来说这无疑是历史性的一刻。
2358 0
|
存储 内存技术 程序员
《操作系统真象还原》——2.2 软件接力第一棒,BIOS
Intel 8086有20条地址线,故其可以访问1MB的内存空间,即2的20次方=1048576=1MB,地址范围若按十六进制来表示,是0x00000到0xFFFFF。不知道硬件工程师当时设计的初衷是什么,总之人家有自己的理由,这1MB的内存空间被分成多个部分。
2029 0
|
存储
《操作系统真象还原》——第2章 编写MBR主引导记录,让我们开始 掌权 2.1 计算机的启动过程
所以,都在内存中运行程序,操作系统和硬件设计都省事了,这可能也是为了方式的统一吧,否则总不能出现某种存储介质后,操作系统和硬件就要付出额外努力去支持。当然,具体原因只有硬件工程师才知道,咱们在此先打住,继续咱们的内容。
1504 0
|
运维 Linux
《操作系统真象还原》——1.5 运行bochs
我们键入的是上面长方形框框中的部分:bochsrc.disk。由于我们刚刚把此文件放到了bochs的安装路径下,bochs找到了它并加载成功。紧接着下面给出的默认选项变成了[6],也就是Begin simulation选项,开始模拟x86硬件平台。
4163 0
|
NoSQL
《操作系统真象还原》——1.4 配置bochs
Bochs既然是模拟硬件的,它就得知道,您需要它模拟的计算机是什么样的,换句话说,在这个虚拟机中有哪些硬件,启动顺序是什么,是从软盘开始,还是从硬盘开始?人家也得像模像样地跟BIOS差不多才行。
2640 0
|
NoSQL Linux iOS开发
《操作系统真象还原》——1.3 操作系统的宿主环境
虚拟机在当今已经不是陌生的概念了,要是在几年前,我还得搬出个概念放在这给大家看看。个人觉得,要解释一个东西是什么,不如直接解释这个东西解决了哪些问题,这样大家自然就从本质上真正理解了它是什么。
2628 0
|
Linux C语言 编译器
《操作系统真象还原》——1.2 我们需要哪些编译器
GCC是由理查德·马修·斯托曼在1985年开始的。他首先扩展一个旧有的编译器,使它能编译C,这个编译器一开始是以Pastel语言所写的。Pastel是一个不可移植的Pascal语言特殊版,这个编译器也只能编译Pastel语言。
1796 0
|
编译器 C语言
《操作系统真象还原》——第1章 部署工作环境 1.1工欲善其事,必先利其器
软件是由编程语言来实现的,即使是编译器本身,它的开发人员都不愿意用底层语言去构建(GCC是用C语言完成的),只有到万不得已的时候才会用汇编语言来写。我们也是一样,能用省事的方法就不要自找麻烦,如果某位大神能直接写机器码,小弟真心恳求与您见上一面,希望您收我为徒,我要当面磕头拜师
1748 0