[音乐]第一周第三讲
上一讲我们介绍了冯.诺依曼计算机的基本结构和存储程序的工作方式
了解到计算机实现的所有任务 都是通过CPU执行程序中的一条一条指令来完成的
那么程序是如何生成并执行的呢? 在本讲中,我们将简要介绍机器语言
汇编语言以及高级语言程序设计的发展过程 并以Hello程序为例,说明程序的启动和执行过程
最后用一个例子来说明不同层次语言之间的等价关系
最早的程序都是用机器语言来编写的
编写的程序记录在纸带或者卡片上面 纸带或者卡片可以穿孔,那么有孔的
表示0,没有孔的地方表示1。
这样的话 那么,有孔和没孔的这种状态,就可以构成一个一个0/1
序列,那么若干个0/1序列可以表示一条指令 输入我们可以通过,按钮。
比如说往上表示0 往下表示1。
或者用开关,或者输出用指示灯
那么通过按钮和开关的状态,或者是纸带或者卡片的穿孔的状态
那这些状态都是有两种状态,很显然都是一个0/1序列
那么这种用0/1序列描述指令,构成的程序就是用机器语言 编写的程序。
机器语言编写的程序,就意味着这个程序当中都是由0和1 构成的这个指令。
比如说这里有几条指令。
第一条 指令是0101 0110。
前面基本上都是 操作码部分,后面是地址部分。
比如说这条指令0101 表示加法,0110表示一个地址
那么这条指令的含义,可以是把累加器的内容 和0110这个地址指出来的第6号单元的内容
相加,加出来的结果继续放到累加器里面 我们下一条指令它的含义是,如果
相加的结果有进位,就是jc这种 可以看出是c表示进位的意思。
如果有进位的话,那么就转到 0100指出的那个单元去执行4号单元里面放的指令
那么前面的这个0010就表示,是一条条件转移指令
啊满足某种条件就转移到后面的这个地址指出来的那个单元 去执行。
所有的这个指令的含义都是用这样的一个0/1序列表示的 在这个0/1序列当中,后面表示的是地址、
操作数或者指令的地址 那么这样用机器语言描述的这种程序
有一个很大的问题,比如说这是,跳转指令
跳转到0100,4号单元这边的指令去执行
那有一个缺陷就是说,如果我们在第4条指令之前
加入一条指令,比如说我们在这儿,第2、 3之间加入一条
加入一条指令以后,原来的第4条指令,就是第1条指令跳转 到该执行的目的地的指令,它就不在4号单元里面
所以这边的0100就要改变,地址就不是0100,应该是 0101了。
如果这个程序纸带已经穿好或者卡片机已经打好孔了 那么这样的话就得重新地进行打孔,因此这种用
机器语言,直接用0和1来编写程序的这种方式 是极其不灵活的,并且书写也很困难,我们得
记好0101表示加,0010表示条件转移 0110表示减法等等。
阅读也不方便,我们看了 这一串0/1序列,我们不知道是什么意思,很难懂
所以,后面程序员编写程序的时候,就不再用0/1序列来
编写程序了,就用符号来表示 这种符号表示的语言叫汇编语言
汇编语言当中,它用符号表示跳转的位置,比如说刚才跳转到4那个位置
这个4它就不直接用0100表示,它就用1个符号来表示
比如说刚才我们做加法,是和0100六号单元里面的数据进行相加
这个6它也不直接出来,而是用一个变量的位置,用这个符号来表示。
这样的话就 简化了问题。
比如说这样的一个程序,用汇编语言来编写,它就直接写成 add
B,然后呢jc L0,然后L0: sub C这样子的
然后B呢就是这边的这个单元,C就是这个单元,L0就是这条指令 表示这条指令。
这种情况下,如果在这个中间,添一条指令的话 这些add
B,jc,包括这个sub C等等都不需要改变
因为这边加一条指令,不影响这些编号 这边是B还是B,这边L0还是L0,C还是C
原来用什么还是用什么,就是不会影响到其他的指令 在第4条指令前加指令的时候,不用改变任何的这些东西
那么这种就是汇编语言,显然汇编语言用这种 形式写程序,比用0和1来写程序要方便得多
那么汇编语言当中,我们就可以用助记符来表示操作码。
比如说0101这个操作码我们用 add这个助记符,一看我们就知道是叫加法 然后呢,我们用标号来表示位置。
然后呢,比如说我们要加这个B这个位置上的一个值,我们就直接 写成B,而不写成这个具体的位置值
然后用助记符表示寄存器,早期没有寄存器,只是累加器
后来的机器有很多寄存器了,就要有寄存器的这个编号
那么在汇编语言当中,它也不出现这个寄存器的 直接的编号,而是用一个助记符,用一个标记来表示
用汇编语言写程序,显然要比这个机器语言要方便得多
首先,增减指令不影响其他指令
不需要修改其他指令,然后也不用记忆这个指令的编码
那记0101表示加,1010表示其他的,编写也方便
可读性比机器语言强,然后我们一看这个程序,大概就知道这个每条指令是干什么
不过,这个带来一个新的问题 就是我们不用0101写程序了,用这种符号写程序了
机器能认识吗?人是方便了,看起来更好懂了。
但是底层的这个运算器 它是不认识add,jc这样的符号的。
它只认识0和1 所以用汇编语言写程序的时候,我们必须将汇编语言写的程序,转换
成机器语言写的程序,这个转换的工作,是由专门的程序来做的
这种程序叫汇编程序,汇编程序用来把 汇编语言写的程序转换成机器语言写的程序
刚才我们讲了这是汇编语言的这个程序 汇编语言程序当然它是由汇编指令构成
这个我们一条一条地用符号表示的指令,我们叫汇编指令。
那什么叫汇编指令? 用一句话来描述,就是用助记符和标号来表示的指令
显然它是和机器指令是一一对应的,只不过机器指令用1和0表示 而汇编指令用符号来表示。
那么这个一条一条的指令,它又能指出什么东西呢?
指令又是什么呢?我们先来看一看这个结构,这是我们上一讲讲的现代计算机的基本的结构
在这个基本的结构里面,我们描述一个动作 这一个动作可以怎样的动作呢?
比如说在这个里面,我们可以描述传送 这样一个动作,我们可以描述,比如说3号单元的内容
传送到0号寄存器里,或者说把1号寄存器的内容
传送到7号单元里面,这这就是一条指令 比如说传送指令,把传送单元的内容装入寄存器,或者反过来
啊反过来就是存储 这个是Ld,load就是装入,然后这个是St
store就是存储,把寄存器的内容存到存储器里面 或者把存储器的内容,装入到寄存器里面。
那上面的指令就是装入指令,下面的就是存储指令 在这个结构里面,我们还可以描述其他的什么动作呢?
我们可以描述把某一个寄存器的内容和另外一个寄存器的内容
在ALU里面做某种运算,比如说做减、 乘 或者除,或者与、 或、 非等等。
所以,我们可以 描述某个寄存器的内容和某个寄存单元的内容
做加法,或者是某个寄存器的内容和另外一个寄存器的内容 做减法、 做乘法等等等等。
我们还可以描述这个指令执行的某一个时刻,执行到这条指令的时候,
如果满足一个什么条件就转到另外一条指令去执行, 而不是取它下一条指令执行。
这个动作我们也可以描述, 等等等等。
所以我们可以看出指令所描述的功能是和 机器的结构相应的。
那么指令就是这样的一些动作的描述。
所以我们可以看出指令当中有操作码 和操作数,或者操作数所在的
地址码,所在的地址的编号叫地址码。
那机器指令实际上是用二进制表示的,汇编指令就是用符号表示的。
也就是说机器指令当中的操作码就是一个01序列,而汇编 指令的操作码就是一个符号,比如说这边的add,这边的sub,
那么指令,我们刚才讲过,它只能描述存或者取一个数,
或者两个数做加减乘除,或者根据某个运算结果判断是否 要转移执行。
啊,指令,是你这种力度的一种动作。
想象一下,用汇编语言来编写复杂的程序是怎样的情形呢。
比如说我们用汇编语言来实现排序啊,矩阵相乘, 因为汇编语言是用汇编指令来描述程序的,
这个汇编指令就是存、 取、 加、 减等等这样的力度。
所以我们要用这么简单的一个对动作的描述的这种指令
来编写程序,这个程序会非常非常长,描述的细节很多。
而且还有一个问题,如果我们用汇编指令来描述的话,
那么每一台机器的汇编指令的格式都是不一样的,所以
对应一台机器上面的汇编语言描述的程序 不能放到另外一台机器上执行。
所以用汇编语言来编写复杂程序 它有两个问题。
一个就是编写的这个程序会很长,另外一个呢,不可能移植。
这里面我们讲的汇编语言和机器语言, 它实际上都是面向机器结构的语言。
它是机器级的语言,它和这个机器的结构相关。
所以用汇编语言来写程序很显然比机器语言写程序要好。
但是,还是很麻烦。
所以后来就产生了用高级语言来写程序的一种方式。
这种高级语言的这种程序 实现方式,它与具体的机器的机构没有关系。
它描述的是算法,所以它是面向算法描述的。
而不是面向的一个一个动作,最基本的动作描述的。
机器级语言描述的是一个一个动作,所以它的面向算法描述的这种方式,
它的描述比面向机器级动作的这种描述方式能力要强得多。
所以一条高级语言当中的一个语句, 它会对应几条,或者十几个动作,甚至几百个动作。
因此它会对应几条,或者几十条,甚至几百条的指令。
它是一种高度抽象的。
那么这个高级编程语言, 它有两种语言,一种是面向过程的,一种是面向对象的方式。
处理的逻辑分顺序结构、 选择结构和循环结构 三类。
那么现在我们的程序员几乎都是用高级语言编写程序了。
所以所有的这个程序都必须要有一个转换,因为在
机器当中,机器硬件是不能够理解高级语言,
而只能理解机器语言,只能理解0和1,因此要有转换。
那么这种转换有两种方式,一种叫编译,一种叫解释。
编译的过程就是把高级语言的源程序 转换成机器级的目标程序,这个机器级
的目标程序可以转换成汇编语言描述的 目标程序,或者直接是机器语言描述的目标程序。
那么执行的时候,只要启动目标程序就可以了。
如果转换成汇编语言描述的 这个程序,那么这个汇编语言描述的程序还要通过
汇编程序转换成机器语言描述的程序, 那么最终在机器上执行的只能是机器语言程序。
另外一种方式是解释程序,就是把高级语言的一个一个语句
一条一条翻译成机器指令,也就是01序列, 翻译完了以后马上就执行。
所以解释程序它是不生成目标文件的。
解释结束,那么这个程序就执行完了。
而编译的方式,它都会生成
目标程序,也就是我们平时讲的可执行文件
大家如果学过C语言程序设计,那么就知道这个最终可执行文件才能在机器上执行。
那么会产生一个可执行文件的是编译的方式,如果是解释程序,那么就没有可执行文件,直接- 就是结果。
[音乐] [音乐]