第六章 子程序结构
一、主程序与子程序的概念
子程序又称为过程,它相当于高级语言中的过程和函数。通常,凡是具有相对独立功能的程序段或需要多次应用的程序段都可以编制成子程序。程序中当需要这段程序时,用调用指令CALL 转到这段程序中去,执行完毕,通过RET 指令返回原来的程序。如下图(1)所示。子程序返回后,从CALL 的下一条指令X 1继续执行主程序。
使用子程序优点:节省编程时间和存储空间,有利于设计一个大而复杂的程序。即可以把一个大而复杂的程序设计成由一个主程序和若干个子程序组成,使用模块化程序设计,减少程序设计复杂性。 使用子程序不足之处:在调用和返回时要进行堆栈操作,增加CPU 开销,使程序速度减慢。
继续
SUR
ENDP X 1: (1)主程序与子程序的关系
(2)子程序嵌套调用
主程序与子程序的概念是相对的。图(2)是一个子程序嵌套调用的例子。
图中,程序1在A、B两处调用程序2,在C处调用程序3,则称程序2和3是程序1的子程序,程序1是主程序;
而程序2和3又分别调用程序4,则称程序4是程序2和3的子程序,程序2和3是主程序。这就是子程序中嵌套子程序。子程序还可以直接或间接调用自己,称为递归子程序和递归调用。
二、调用指令CALL 和返回指令RET
(参见指令系统p.98)
CALL 调用指令
RET 返回指令
由于子程序和调用程序可以在同一个段中,也可以不在同一段中,因此这两条指令的格式如下:
1、调用指令CALL DST
CALL指令语句实现子程序(即过程)的调用。调用结束后,要由所调用的子程序RET指令返回到CALL指令的下一条指令(即返回调用断点),因此执行CALL指令时要进行进栈操作。具体分为直接调用和间接调用。
直接调用:目标地址直接出现在CALL指令语句中,DST就是过程名(即子程序名)。
间接调用:由16位通用寄存器或者存储单元提
供调用地址。
(1)段内直接调用
格式:CALL DST
执行的操作:Push(IP) ;当前IP值进栈
(IP)←(IP)+D16
;目标地址装入IP,程序转移指令操作分二步:
第一步,是把子程序的返回地址(即调用程序中CALL指令的下一条指令的地址)存入堆栈中,以供子程序返回主程序时使用。
第二步操作则是转移到子程序的入口地址去继续执行。指令中DST给出转向地址(即子程序入口地址,也即子程序的第一条指令的地址)。D16是机器指令中的位移量,是转向地址和返回地址之间的差值。
例:CALL SB1
子程序名SB1是NEAR型标号
(2)段间直接远调用
格式:CALL DST 或CALL FAR PTR DST 执行的操作:Push(CS); 返回地址的段地址入栈Push(IP) ;返回地址的偏移地址进栈
(IP)←DST指定的偏移地址
(CS)←DST指定的段地址
段内调用和段间调用的堆栈操作如下图所示。
图(a )段内CALL 调用后,由于CS 保持不变,只修改IP 的值,所以返回地址只有IP 的值压入堆栈中。图(b )在段间CALL 调用后,由于调用程序和子程序不在同一个段中,调用后CS 、IP 值都发生了变化,所以返回地址的保存以及转向地址的设置都必须把段地址CS 考虑进去。
2、返回指令RET
(1)段内近返回RET
执行的操作:(IP)←POP()
返回 地址
(SP)←(SS)(SP)←(b
)段间CAll 执行后
返回 地址 (SS)×(SP)←(a) 段内CAll 执行后
就是把SP所指的栈顶一个字的内容弹回到指令指针IP中,且SP加上2。
(2)段间远返回RET
执行的操作:(IP)←POP()
(CS)←POP()
这就是把SP所指的栈顶的一个双字的内容弹回到指令指针IP和代码段寄存器CS中,第一个字弹回到IP,SP加上2,第二个字弹回到CS,SP再加2。
(3)带参数的返回指令RET (P.100)
格式:RET EXP
EXP——表达式,计算结果是常数N 执行的操作:
完成RET指令操作,再执行(SP)←(SP)+D16
指令在返回地址出栈后再修改堆栈指针,等于把CALL指令调用以前入栈的D16个字节数弹出堆栈作废,故一般D16是一个偶数。
例如:RET 8和RET 6等。
6.1 子程序的设计方法
6.1.1过程定义后操作
格式:procedure_name PROC Attribute
RET
procedure_name ENDP
procedure_name:过程名,任起。
Attribute:类型属性,FAR或者NEAR。
过程定义中,PROC与ENDP必须成对使用。
过程中,原则上至少有一条RET指令,但也可以多于一条,不一定放在过程最末一条指令。通过RET返回调用者。
过程名:被CALL指令调用,是子程序入口的符号地址,是标号。它具有三个属性:段属性、偏移地址和类型属性。
指出过程类型十分重要,它是汇编程序生成CALL和RET指令目标代码的依据。
?过程类型为NEAR型:供段内调用的子程序。此时调用它的CALL指令生成三字节目标代码,过程中的RET是近返回的目标代码。
?过程类型为FAR型:供段间调用的子程序。此时调用它的CALL指令生成五字节目标代码,过程中的RET是远返回的目标代码。
所以,过程的类型决定了CALL和RET指令类型。
过程类型确定原则:
(1)调用程序和过程在同一个代码段中,则使用NEAR属性
例 6.1 调用程序和子程序在同一个代码段CODE SEGMENT
MAIN PROC FAR
ASSUME CS:CODE
┇
CALL SUBR1
┇
RET
MAIN ENDP
SUBR1 PROC NEAR
┇
RET
SUBR1 ENDP
CODE ENDS
END
例中,MAIN和SUBR1都属于CODE段,所以SUBR1定义为NEAR型属性。这样主程序中CALL SUBR1语句及SUBR1中的RET都是NEAR型。对MAIN主程序,定义为FAR属性,是因为将MAIN当作DOS FAR调用的子程序。
例6.2调用程序和过程不在同一个代码段中,则使用FAR属性。
SEGX SEGMENT
ASSUME CS:SEGX
┇
SUBT PROC FAR
┇
RET
SUBT ENDP
┇
CALL SUBT
┇
SEGX ENDS
;
SEGY SEGMENT
ASSUME CS:SEGY
┇
CALL FAR PTR SUBT
┇
SEGY ENDS
例中,子程序SUBT在SEGX段中定义,它有两处被调用:一处是与它在同一段的SEGX段内,另一处是在另一段SEGY内。当被SEGY段调用时,子程序SUBT和CALL SUBT语句分属二个不同的段,则SUBT属性为FAR以适用SEGY段调用的需要。这样不论在SEGX段和SEGY段对SUBT的
调用,都具有FAR属性了,不会发生错误。如果使用NEAR属性,在SEGY段内对它的调用将出错。
6.1.2 子程序的调用和返回
在执行CALL和RET指令时,CPU自动执行堆栈操作。
CALL指令:将返回地址压入堆栈,RET指令,将返回地址从栈中弹出到IP(远返回则弹出到IP 和CS)。
例:主程序MAIN在一个代码段中,(CS)=0500H 子程序PRO_A,PRO_B,在另外一个代码段中,调用关系如下:
MAIN
PRO_A ENDP PRO_B PROC
RET PRO_B ENDP
设SP初值为0100H,调用过程堆栈变化情况如图:
(SP
(1)(SP)=0100H
(SP
(2)(SP)=00FCH
(SP
(3)(SP)=00FAH
(1) MAIN 调用PRO_A 前
(2)MAIN 调用PRO_A 后
(3)PRO_A 调用PRO_B 后
(4)PRO_B 返回PRO_A 后
(5)PRO_A 返回MAIN 后
使用注意点:要保证子程序正确返回调用程序,
要求在执行RET 指令前,SP 指向返回地址,所以在子程序中,PUSH 和POP 操作必须是成对的。调用结束返回后,SP 必须恢复到调用前的值。
例:习题6.1(p.240)下面的程序有错吗?若有,
请指出错误。
(SP
(4)(SP)=00FCH
(5)(SP)=0100H (SP
CRAY PROC
PUSH AX
ADD AX,BX
RET
ENDP CRAY
解:该子程序有二个错误:
(1)末行ENDP与子程序名CARY 写颠到了。
(2)子程序中,有PUSH AX ,但是没有
POP AX,该子程序不能正确返回调用程序。
6.1.3 保存与恢复寄存器
由于主程序与子程序是分开编写的,所以使用的寄存器往往会发生冲突。保存与恢复寄存器又称保护现场和恢复现场。
具体要求是:在子程序返回主程序后,CPU中工作寄存器的状态必须恢复到调用前的值,包括程序状态字PSW、各数据寄存器、地址寄存器等。
一般方法:进入子程序执行PUSH操作保护,返回前执行POP操作恢复。例如:
例如:SUBT PROC NEAR
PUSH AX
PUSH BX
PUSH CX
┇
POP CX
POP BX
POP AX
RET
SUBT ENDP
基本考虑方法:在主程序和子程序之间传递参数的寄存器不必保存,特别是子程序向主程序回送结果的寄存器不能保存,否则会产生错误。其他的在子程序中用到的寄存器应该保存。
6.1.4 子程序的参数传送
参数传送是调用程序和子程序之间的信息传递,分调用参数和返回参数。
调用参数(又称入口参数):由调用程序提供给子程序工作的初始数据.
返回参数(又称出口参数):由子程序将执行以后的结果数据回送给调用程序。
参数传递有以下几种方法:
1、通过寄存器传递参数——主程序和子程序
之间通过约定的寄存器传递参数。
调用前,主程序将调用参数放入约定的寄存器中;进入子程序后,从约定的寄存器中取出参数执行子程序;执行完毕,将结果存入约定的寄存器,返回主程序后就可获得结果。这是最常用的一种方法。
特点:简单、直观、使用方便,但参数个数受寄存器限制,不宜过多。
例6.3十进制数到十六进制数转换程序。
要求:从健盘输入十进制数转换成二进制,然后把该数以十六进制形式在屏幕上显示出来。采用子程序结构,各子程序功能如下:
DECIBIN:从键盘取得十进制数,转换成二进制后保存在BX中。
BINIHEX:用十六进制形式显示BX中的数。
CRLF :回车、换行,调用该子程序后,屏幕上滚一行,光标回到起始位置,以避免屏幕上显示重叠。
必须指出:在各个子程序之间用BX寄存器传递信息。
源程序如下:
;主程序
DECIHEX SEGMENT
ASSUME CS:DECIHEX
MAIN PROC FAR
REPEAT:CALL DECIBIN
CALL CRLF
CALL BINIHEX
CALL CRLF
JMP REPEAT
MAIN ENDP
·DECIBIN子程序:
(1)十进制数转换成二进制算法:将十进制数按权展开相加。
例:有十进制数:9587
9587=9×103+5×102+8×101+7
=(((0×10+9)×10+5)×10+8)×10+7 式中:0就是结果寄存器的初值,式中的基本运算就是乘法和加法。采用二进制乘法指令和加法指令,就得到了二进制的结果。
(2)程序流程图
先将输入一位字符的ASCII码转换成BCD数,然后判断其有效性。若为0-9之间数字,表示输入有效,进行转换运算,并可继续输入;否则子程序返回。最后转换结果在BX中,所以输入的最大数是65535,转换后的结果为0FFFFH,超出此范围,结果错误。程序流程图如下:
源程序:
DECIBIN PROC NEAR
MOV BX,0
NEWCHAR:MOV AH,1
INT 21H ;(AL)=输入字符ASCII码
SUB AL,30H ;转换成二进制
JL EXIT ;(AL)<0,转结束
CMP AL,9 ;(AL)>9?
JG EXIT ;是,转结束
CBW ;否,进行转换运算
XCHG AX,BX
MOV CX,10
MUL CX
XCHG AX,BX
ADD BX,AX
JMP NEWCHAR ;继续输入字符EXIT:RET
DECIBIN ENDP
。子程序BINIHEX :将BX中二进制数转换成十六进制在控制台屏幕显示。
;
BINIHEX PROC NEAR
MOV CH,4
ROTATE:MOV CL,4
ROL BX,CL
MOV AL,BL
AND AL,0FH
ADD AL,30H
CMP AL,3AH
JL PRINTIT
ADD AL,07H
PRINTIT:MOV DL,AL
MOV AH,2
INT 21H
DEC CH
JNZ ROTATE
RET
BINIHEX ENDP ;——————————————————————————————————。子程序CRLF:回车,换行
CRLF PROC NEAR
MOV DL,0DH
MOV AH,2
INT 21H
MOV DL,0AH
MOV AH,2
INT 21H
RET
CRLF ENDP ;————————————————————————————————————DECIHEX ENDS
END MAIN
2、如过程和调用程序在同一源文件(同一程序模块)中,则过程可以直接访问模块中的变量。
例:6.4主程序MAIN和过程PROADD在同一源文件中,要求用过程PROADD累加数组中的所有元素,并把和(不考虑溢出的可能性)送到指定的存储单元中去。
源程序如下:
DATA SEGMENT ;定义数据段
ARY DW 100 DUP(?)
COUNT DW 100
SUM DW ?
DATA ENDS
;
CODE SEGMENT ;定义代码段
MAIN PROC FAR
教案
讲稿 第六章算法与程序设计 [旧课复习]: 复习内容: 1.PowerPoint幻灯片的基本制作方法 2.PowerPoint 幻灯片的动画设计 复习目的:加强学生熟练掌握PowerPoint基本操作 复习时长:大约5分钟 [新课导入]: 导入方式:展示一个自制应用程序 导入目的:让学生初步了解程序设计的应用理念 导入时长:大约5分钟 [新课讲授]: 重点:掌握算法的基本特征;掌握结构化程序设计方法。 难点:掌握选择结构、循环结构的特点。 方法:运用多媒体辅助教学,采用案例教学和任务驱动等教学法。 6.1 计算机求解问题的方法 (1)界定问题。 (2)分析问题。 (3)建模。 (4)分析模型建立算法。 6.2 算法及算法的描述 6.2.1 算法的定义 算法(Algorithm)是指完成某一特定任务所需要的具体方法和步骤,是有穷规则的集合。 6.2.2 算法的基本特征
算法是程序设计的“灵魂”,算法+数据结构=程序。算法独立于任何具体的程序设计语言,一个算法可以用多种程序设计语言来实现。 算法具有以下基本特征。 (1)输入:一个算法有0个或多个输入,用以表征算法开始之前运算对象的初始情况。(2)输出:一个算法必须有一个或多个输出,输出是算法计算的结果,没有任何输出的程序是没有意义的。 (3)确定性:算法对每一步骤的描述必须确切而无歧义,以保证算法的实际执行结果精确地符合要求或期望。 (4)有穷性:算法必须在有穷步骤内完成任务,并且每一步骤都可以在有穷时间内完成。(5)可行性:算法中描述的操作都是可以通过已经实现的基本运算,执行有限次数来实现。 6.2.3 算法的评价 对于算法的评价有两个基本标准:时间复杂度和空间复杂度。 所谓时间复杂度,即执行这个算法需要多少时间。 所谓空间复杂度,即执行这个算法需要占用多少资源(可以理解为占用了多少计算机存储单元)。 6.2.4 算法的描述 计算机算法无非是将人脑抽象出的模型程序化,而求解问题的关键还是在于人类本身的思维。算法的描述是基于一种形式地表达 6.2.5 算法的表示 常用的描述工具有:流程图、N-S图、PAD图、伪码等。 1.流程图 流程图是算法表达最常用的一种方法。流程图是一种用程序框、流程线及文字说明来表示算法的图形。在程序框图中,一个或几个程序框的组合表示算法中的一个步骤,带有方向箭头的流程线将程序框连接起来,表示算法步骤的执行顺序。流程图中常用的元件 起止框表示一个算法的起始和结束,是任何流程图不可少的 输入、输出框表示一个算法输入和输出的信息,可用在算法中任何需要输入、输出的位置处理框赋值、计算。算法中处理数据需要的算式、公式等分别写在不同的用以处理数据的处理框内。 判断框判断某一条件是否成立,成立时在出口处标明“是”或“Y”;不成立时标明“否”或“N” 流程线连接程序框,带有控制方向
第四章结构化程序设计的三种结构 4.1 顺序结构程序设计 一、结构化程序设计的程序结构 顺序结构、分支结构/选择结构、循环结构 二、C语言语句 1、9种控制语句 2、表达式语句 3、特殊语句 三、格式化输出--printf()函数printf()函数的作用:向计算机系统默认的输出设备(一般指终端或显示器)输出一个或多个任意类型的数据。 printf()函数的一般格式 printf("格式字符串" [,输出项表]); 1、"格式字符串"也称"转换控制字符串",可以包含三种字符 (1)格式指示符。 格式指示符的一般形式如下: %[标志][宽度][.精度][F|N|h|L][类型]常用的标志字符如表3-1所示,常用的宽度指示符如表3-2所示,常用的精度指示符如表3-3所示,长度修饰符如表3-4所示,类型转换字符如表3-5所示。 (2)转义字符 '\n'就是转义字符,输出时产生一个"换行"操作。 转义字符通常起控制作用 (3)普通字符──除格式指示符和转义字符之外的其它字符。格式字符串中的普通字符,原样输出。 例如printf("radius=%f\n", radius);语句中的"radius="是普通字符。 2.输出项表 输出项表是可选的。如果要输出的数据不止1个,相邻2个之间用逗号分开。下面的printf()函数都是合法的: (1)printf("I am a student.\n"); (2)printf("%d",3+2); (3)printf("a=%f b=%5d\n", a, a+3); 必须强调:"格式字符串"中的格式指示符,必须与"输出项表"中、输出项的数据类型一致,否则会引起输出错误3、格式指示符 输出不同类型的数据,要使用不同的类型转换字符。 (1).类型转换字符d──以带符号的十进制整数形式输出。 main() {int num1=123; long num2=123456; /*用3种不同格式,输出int型数据num1的值*/ printf("num1=%d,num1=%5d,num1=%-5d,num1=%2d\n", num1,num1,num1,num1); /*用3种不同格式,输出long型数据num2的值*/ printf("num2=%ld,num2=%8ld,num2=%5ld\n",num2,num2,num2); printf("num1=%ld\n",num1);
中国海洋大学本科生课程大纲 课程属性:公共基础/通识教育/学科基础/专业知识/工作技能,课程性质:必修、选修 一、课程介绍 1.课程描述: 结构化程序设计主要讲授C语言。C语言是一种广泛使用的计算机程序设计语言,既有高级语言的特点,又有低级语言的特点,不依赖计算机硬件。它既可以用来设计系统软件,也可以用来设计应用软件。本课程针对低年级学生开设,课程基本内容包括:顺序结构程序设计、选择结构程序设计、循环结构程序设计、数组、函数、指针等。通过课程学习,要求学生掌握C程序的设计和实现方法,并以之解决实际问题。 2.设计思路: 本课程培养低年级学生的程序设计和实现能力。课程内容从数据类型、运算符、表达式、语句、程序结构等基本知识开始,到数组、函数、指针等知识,相辅相成、逐层深入,构建起C语言体系。 数据类型是指C语言中数据的表示形式,基本包括整型、浮点型、字符型等。常用运算符有算术运算符、赋值运算符、关系运算符、逻辑运算符等。基本程序结构包括顺序、选择、循环三种。数组、函数能够使得程序更加简洁紧凑,有利于实现模块化、结构化。指针使得程序员能够管理内存,实现更多的功能。 3.与其他课程的关系: 后置课程:《C++》、《数据结构》、《计算机图形学》、《数字图像处理》等。 二、课程目标
本课程的目标是培养低年级数学类专业学生的程序设计能力、程序实现能力,并以C语言解决实际问题的能力。 到课程结束时,学生应该 (1)具有分析问题的能力,根据实际问题设计出解决方案。 (2)具有编写、调试程序的能力,根据实际输入数据调试程序中可能出现的错误,并得到正确结果。 三、学习要求 要完成所有的课程任务,学生必须: (1)按时上课,上课认真听讲,积极参与随堂练习。本课程将包含较多的随堂练习,出勤率和课堂表现是成绩考核的组成部分。 (2)按时完成练习作业。只有按时提交作业,才能掌握课程所要求的内容。延期提交作业需要提前得到任课教师的许可。 四、教学进度
第六章结构化程序设计 一、选择题 1、W AIT命令用于让用户输入一个。 A)数字B)字符C)字符串D)以上都是 2、在交互式输入命令中,可以接受逻辑型数据的命令包括______。 A)INPUT和ACCEPT B)WAIT和INPUT C)INPUT和@…GET D)INPUT和@…SAY 3、执行命令ACCEPT″请输入数据:″TO XYZ 时,可以通过键盘输入的内容包括______。 A)字符串B)数值和字符串 C)数值,字符串和逻辑值D)数值,字符串,逻辑值和表达式 4、执行命令INPUT″请输入数据:″TO AAA时,如果要通过键盘输入字符串,应当使用的定界符包括 ______。 A)单引号B)单引号或双引号 C)单引号、双引号或方括弧D)单引号、双引号、方括弧或圆点 5、在VFP中,可以通过键盘接受数值的命令有_______。 A)ACCEPT B)ACCEPT和W AIT C)INPUT和ACCEPT D)INPUT和@ 5,10 SAY...GET.. 6、比较W AIT、ACCEPT和INPUT三条命令,需要以回车键表示输入结束的命令是_____。 A)W AIT、ACCEPT、INPUT B)WAIT、ACCEPT C)ACCEPT、INPUT D)INPUT、WAIT 7、以下关于ACCEPT命令的说明,正确的是______。 A)将输入作为字符接收B)将输入作为数值接收 C)将输入作为逻辑型数据接收D)将输入作为备注型接收 8、结构化程序设计所规定的三种基本控制结构是_______。 A)输入,处理,输出B)树型,网型,环型C)顺序,选择,循环D)主程序,子程序,函数 9、能将高级语言编写的源程序转换成目标程序的是_______。 A)编程程序B)编译程序C)解释程序D)链接程序 10、VFP中的DO CASE-ENDCASE语句属于_______。 A)顺序结构B)选择结构C)循环结构D)模块结构 11、当前数据库中有五个字段:学号(C,4)、姓名(C,6)、政治(N,3.0)、英语(N,3.0)、数学(N,3.0),记录指 针指向一个非空的记录。要使用SCATTER TO X命令把当前记录的字段值存到数组X中,数组X ______。 A)不必事先定义 B)必须用DIMENSION X 事先定义 C)必须用DIMENSION X(5)事先定义 D)必须用DIMENSION X(1),X(2),X(3),X(4),X(5)事先定义 12、要判断数值型变量Y是否能够被7整除,错误的条件表达式为______。 A)MOD(Y,7)=0 B)INT(Y/7)=Y/7 C)0=MOD(Y,7) D)INT(Y/7)=MOD(Y,7) 13、在VFP中,命令文件的扩展名是______。 A)TXT B)PRG C)DBT D)FMT 14、以下有关VFP中过程文件的叙述,其中正确的是______。 A)先用SET PROCEDURE TO 命令关闭原来已打开的过程文件,然后用DO <过程名>执行 B)可直接用DO <过程名>执行 C)先用SET PROCEDURE TO <过程文件名>命令打开过程文件,然后用USE <过程名>执行 D)先用SET PROCEDURE TO <过程文件名>命令打开过程文件,然后用DO <过程名>执行 15、执行SET DEVICE TO PRINT 命令之后,能在打印机上实现输出的命令是______。