从物理层面解释,为什么在键盘上输入 abc,电脑屏幕上就会显示 abc?
从汇编的角度解释吧
我为什么用汇编解释呢,因为汇编是介于软件与硬件之间的东西,它的本质是0和1
0和1在逻辑电路上就是低电位与高电位
然而逻辑电路的东西在这一篇回答里又讲不完,所以就先讲汇编如何实现输入的实时屏幕输出吧
直接上代码吧
方便理解,用LC-3汇编来实现
LC-3有以下规则
16位地址和指令长度
常用寄存器为R0-R7,但人为编写时一般不会用R0和R7,后面你会知道为什么的
“;”是comment
如果单纯只是为了将输入的字符输出到屏幕,然后就halt那么只需占用两个内存地址
假设从x3000地址开始
代码就是
.ORIG x3000 ;Indicate the starting address
LOOP TRAP x20 ;Char R0 = Console.Read()
TRAP x21 ;Console.Write(R0)
TRAP x25
.END ;End Program
x3000这个counter,其instruction是等待键盘输入一个字符,接收到字符后,该字符的ASCII值被储存到寄存器R0,结束,且PC+1,(PC的全称是Program Counter,其包含下一个将被执行的指令的地址)
假设我们输入“0”,那么,在x3000结束后,PC为x3001,R0为x0030(即0的ascii编码)
然后到x3001这个counter,其instruction是输出R0到屏幕,那么该instruction结束后,PC为x3002,屏幕显示ascii x30的字符即“0”
x3002,结束程序,其实可以不用这个TRAP x25,LC-3完全是给学生设计的,TRAP x25后,PC会调到预设定位置输出--------halting processor---------告诉你程序结束,这一行不要也行,但是后面的.end 一定是要有的
实际效果是这样的
https://www.zhihu.com/video/978632881849061376那么如何实现多次输入并实时显示到屏幕呢
LC-3支持label,我们只需在敲代码时在x3000那里加个label比如叫LOOP
然后在x3002 写BRnzp指令(BR指令二进制解释如图)
n为negative,z为zero,p为positive,该指令将对R0判定,如果符合11-9的条件,就跳转到8-0位或label所指的地址
回到代码,代码如下
.ORIG x3000 ;Indicate the starting address
LOOP TRAP x20 ;Char R0 = Console.Read()
TRAP x21 ;Console.Write(R0)
BRnzp LOOP ;unconditionally jump to LOOP
.END ;End Program
我在这里写的是BRnzp,及11-9都为1,意味着R0<0 AND R0=0 AND R0>0时跳转到loop,就是无条件跳转到loop
那么你每次输入完并输出到屏幕后,执行完BR指令后都会跳回到LOOP,这其实就是循环结构,这种跳转指令,高级语言中的for啊,while啊,loop这些循环结构,if什么的判断,都是这么实现的
在这里很容易理解了,就是个不断输入输出的死循环,暂时先不考虑怎么跳出去,就是为了实现连续输入输出而已
演示如下
https://www.zhihu.com/video/978652764931313664那么怎么跳出循环呢,在高级语言编程时,在运行最基本的console application的时候,比如Windows下的CMD,Linux的命令行界面下,最常见的都是输入一行指令并按回车键提交。大多数高级语言中比如C#的readline,等待用户键盘键入也都是在按回车时执行下一行。
其实很简单
回车,本质上也是一个字符,在ASCII中有对应的值,我们只需某一次输入有没有这个值就可以了
上面的BRnzp我们稍微修改一下
程序每次接收并实时输出所接收到的字符后
也就是执行完x3001后,x3002 来做一道简单的加减法,回车的ASCII值是x000A,也就是十进制的10
由于每次执行完x3001后,我们输入的字符的ASCII值都被保存在了R0中,那么就让R0-10,如果R0 = R0 - 10 =0,即可判定用户键入了回车键,程序要跳出循环往下走了
具体代码如下
.ORIG x3000 ;Indicate the starting address
LOOP TRAP x20 ;Char R0 = Console.Read()
TRAP x21 ;Console.Write(R0)