第六章 子程序程序设计
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
• • • • • • • • •
MASM中嵌套的结构
• MASM允许用户对结构定义进行嵌套,在一些情况下,这就允许 一个结构的某些域是结构本身。例如: • point STRUC • x db ? • y db ? • point ENDS • Rectangle STRUC • UpperLft point ;左上角坐标(x,y) • LowerRt point ;右上角坐标(x,y) • Rectangle ENDS • 返回
使用STRUC组织用户数据
• 使用STRUC组织用户数据很容易,• 例如定义一个包含 最初名、最后名和中间分隔符的结构FullName,可以 使用代码: FullName STRUC Firstname db 15 dup(?) Initial db ? LastName db 24 dup(?) FullName ENDS • 结构定义并不占用空间,但MASM在遇到结构中的 域时就会为它分配空间。 • 返回
为结构分配空间
• 前面的定义只是为该结构定义了一个模板,• 但MASM 还未分配空间。• 用户可以为FullName数据结构和其它 数据类型的实例分配空间并加以初始化。• 下面的例子 创建FullName结构的两个实例,• Naba和Mitch,还创建 含有10个FullName结构的数组,它可以通过People进行 访问。 • Naba FullName {} • Mitch FullName {} • People FuFra Baidu biblioteklName 10 dup({}) • 返回
•
1) 2) 3) 4) 5) 6) 7) 8) 9)
算法:
设要显示的数据在BX中 准备除数 CX10000,转8) 准备除数CX1000,转8) 准备除数CX100,转8) 准备除数CX10,转8) 准备除数CX1,转8) 结束 准备被除数: DX 0, AXBX 执行DIV CX,结果 商在AX(实际上在AL中)中,余数在DX中并将其赋给BX,为下一 步做准备 显示商 返回
十二算法
• 思路:
123=1*100+2*10+3 =(((0*10)+1)*10+2)*10+3 X=X*10+Y
•
算法:
1) 2) 3) 4) 5) 6) 7) 设BX中存放最终二进制数,初值为0 从键盘输入一个字符,如1,则(al)中为其ASCII AL(AL)-30H ;将ASCII变成实际的数值 判断0<=(AL)<=9?,不是转7) 执行CBW命令将ALAX BX(BX)*10+AX,转2) 结束
第六章 子程序程序设计
• 在一个程序中,当不同的地方需要多次使用的某程序段 (即完成一个给定功能的程序段)常常单独编制一指令序 列。在程序运行时,若需要这个给定功能,就转移到这个 指令序列,待指令执行完后,又返回到原来位置继续执行。 这个单独编制的指令序列就叫子程序,转移到子程序称为 调用子程序。 定义子程序的伪指令 子程序的结构类型 子程序的数据传送方法 结构伪指令 代码转换 递归程序设计 多模块之间的连接
访问嵌套结构中的域
• • • • • • • • • • • 假设定义了一个变量R1,它的类型是Rectangle,则可以用下列语句访问域x坐标和域 y坐标: mov al,R1.UpperLft.x mov ah,R1.LowerRt.x mov bl,R1.UpperLft.y mov bh,R1.LowerRt.y 例外: ThreeDPt STRUC point z db ? ThreeDPt ENDS 在该定义中只是将point的定义包含到ThreeDPt结构中,• 就好象用户自己为x和y输 入定义。如果有一个类型为ThreeDPt的变量T,则分别用T.x、T.y和T.z来分别访问这 些域。由于在point说明中没有标号,MASM无法获取point中那些域的句柄。这看起 来是一个缺点,• 但它具有优越性。STRUC这一特性使MASM能处理继承性——对于 面向对象的程序设计这是最基本的要求之一。 返回
•
返回
二十算法与思路
•
– – – – – – – – –
思路:
4567H=17767D 4567H/10000=1 余 7767D=1E57H 1E57H/1000=7 余 767D=02FFH 02FFH/100= 7 余 67D=0043H 0043H/10=6 余 7D=0007H 0007H/1=7 余0 1DL DL(DL)+30H AH02h 执行INT 21H;将在屏幕上显示字符1
10) 11)
返回
代码转换举例
• • • • • • • • • • • • • • • • • • • • • • DEC_BIN PROC FAR ;BX中存放从键盘输入的十进制数转换的二进制数 MOV BX,0 ;BX中存放输入的数值 NEWCHAR: MOV AH,01H INT 21H ;(al)为ASCII字符 SUB AL,30H ;ASCII TO binary JL EXIT ;jump if <0 CMP AL,0AH ;is it >9d? JGE EXIT ;yes not decimals digit CBW ;byte in AL to word in AX ;digit is now in AX ;将BX乘上10 XCHG AX,BX ;exchange ax and bx MOV CX,10 ; MUL CX ;将AX乘上10 ADD BX,AX ;将AX与BX相加并送BX JMP NEWCHAR ;get next digit EXIT : RET DEC_BIN ENDP 返回
–
算法及思路
•
• • • •
二 十: 向屏幕输出时,通常输出十进制数,因为符合人们的习惯,但在计算机内部为十六 进制,如将7BH输出到屏幕,必须将其化成十进制数123的ASCII码31H、32H、 33H再分别输出到屏幕。使用DOS中断的02号功能,显示字符到屏幕 mov ah,02h int 21H 算法与思路 举例: 十二 二十 返回
4. 结构伪指令
• 到目前为止,允许分配和命名指定大小(字节、字和双字等)的变量的 指令,但大多数应以程序是使用相关的变量组而非单个变量。例如保存 人名的一个应用程序,如果该程序要保存人的最后名、最初名和中间的 词首分隔符,每个名是三个独立的文本串。可以使用独立的BYTE指令 来分配每个串,但将这三个串放在一起作为一组分配是方便的。MASM 中的STRUC指令正好提供这种功能——定义一个由(可能是)• 不同类 型变量组成的整体数据结构。 • 使用STRUC组织用户数据 • 为结构分配空间 • 在汇编过程中初始化结构域 • MASM中嵌套的结构 • 访问结构中的域 • 访问嵌套结构中的域 • 返回
1. 2. 3. 4. 5. 6. 7.
1. 定义子程序的伪指令
子程序的结构如下: <子程序名> PROC [NEAR/FAR] … RET [n] … <子程序名> ENDP 调用指令: CALL <子程序名> 子程序的类型有NEAR和FAR(缺省为NEAR)• ,和调用程序在同一代码 段中的子程序用NEAR,和调用程序不在同一代码段中的子程序使用 FAR属性,当然定义为FAR的子程序在同一段也可调用。 在执行CALL语句时,将CALL语句的下一语句的IP(或CS和IP)压栈, 在执行子程序时中的RET[n]语 • 句时,系统将用栈顶的内容弹出并更新IP (或IP和CS)的值,若有[n]系统将再多弹出n个字节(n必须为偶数)。 • 返回
CALL指令祥解
• 段内调用:
– 直接调用
• CALL <过程名>
– 间接调用
• • • • CALL CALL CALL CALL reg /mem BX CX WORD PTR 20H[BX][SI]
– 如果在段内调用远过程
• CALL FAR PTR <过程名>
•
返回
2. 子程序的结构类型
⑴ 一个主程序调用一个子程序
⑵ 多层嵌套调用:
子程序再调用子程序,要格外注意程序中的堆栈变化,要确 保子程序在每次返回时,SP指向的是正确的返回地址,而不 是数据或其它信息。 ⑶ 递归调用子程序: 子程序调用自身,这种结构程序短效率高,它是嵌套调用的 一种特殊情况 返回
3. 子程序的数据传送方法
通常有五种方法: ⑴ 直接访问: 子程序和调用程序在同一程序模块中,则子程序可直接访问模块中的 变量 ⑵ 使用PUBLIC定义的公共(全局)变量和EXTRN说明的外部变量。 ⑶ 通过寄存器 ⑷ 通过堆栈 ⑸ 通过公共数据区 各模块分别定义一个同名的数据段,并用组合类型COMMON合并为 一个覆盖段,这样变量即成为本模块的局部变量,可直接引用。 • 返回
在汇编过程中初始化结构域
• • • • • • • • • 上例中用户说明结构变量时,• MASM并不初始化这些域为任何值(实际上为0)。用户也可在定义结 构时进行初始化: FullName STRUC Firstname db '---------------' Initial db '-' LastName db '------------------------' FullName ENDS 使用这种定义,则用FullName类型说明的任何变量在缺省时其中的域都初始化为短线。 如果用户所需的大多数(或所有的)结构都以相同的域值开始,那么缺省的初始化是很有用的。• 但 通常用户需要将每个结构实例初始化为不同的域值。• 例如上述的变量Naba和Mitch要包含类似于 "Naba"和"Mitchell"这样的串,• 而不是短线。MASM提供了使用指定值替换缺省值的手段。当定义一 个结构变量的实例时,可以在参数域的"{"和"}"(也可使用"< >")符号之间包含一个初始化表。 Naba FullName {"Naba"," ","Barkakati"} Mitch FullName {"Matchell"," ","Waite"} 用户可以只初始化结构中的某些域,如果初始化表中某一项为空,MASM就给该域使用缺省值。如: Jonathon FullName {"Johnny"} ;Initial/Lastname=-John FullName {,"A"} ;First/Lastname=-Jon FullName {,,"Apple"} ;First/Initial=--Johnny FullName {"John"," "} ;Last=----------返回
访问结构中的域
• • • • • • • • • • • • 当用户说明了某种结构类型的变量时,MASM将结构的第一字节的偏移设 置为该变量名,用户可以使用地址表达式了访问该结构的域。访问方式: <变量名>[位移量] <变量名>.<域名> 例: MOV al,Naba+15 MOV al,Naba.Initial MOV al,Naba.Firstname[4] LEA si,Naba.Lastname 若将Naba的地址已被装入ES:[BX]中,如果要访问LastName,使用指令 MOV al,ES:[BX].Lastname 若Lastname是由几个结构共享的域名,将会发生错误。 返回
•
5. 代码转换
• • 主要有以下几种情况: 十 二: 从键盘输入十进制数,但计算机在接受时,接受的是数字的ASCII码,如输入"123", 而计算机接受的是31H,32H,33H三个ASCII码,因此必须将其转换成123(7BH)。
– 使用DOS中断的01号功能从键盘接受一个字符
MOV AH,01h INT 21H ;(al)中为ASCII
代码转换举例
BIN_DEC PROC FAR MOV CX,10000D ;DEVIDE BY 10000 CALL DEC_DIV MOV CX,1000D ;DEVIDE BY 1000 CALL DEC_DIV MOV CX,100D ;DEVIDE BY 100 CALL DEC_DIV MOV CX,10D ;DEVIDE BY 10 CALL DEC_DIV MOV CX,1D ;DEVIDE BY 1 CALL DEC_DIV RET BIN_DEC ENDP ;-----------------------------------------------------------------------DEC_DIV PROC NEAR ;打印商到屏幕上 ;被除数在(DX,AX)里,除数在CX中 MOV AX,BX MOV DX,0 ;将高字赋0 DIV CX MOV BX,DX ;余数在BX中 MOV DL,AL ;商在DL中 ;显示DL到屏幕上 ADD DL,30H ;转换成ASCII MOV AH,02h ;INT 21H的02号功能显示DL中的ASCII到屏幕上 INT 21H RET DEC_DIV ENDP