📄 汇010.txt
字号:
21H
.UNTILCXZ
MOV DL, CR ;下面六条指令显示回车、换行
MOV AH, 2
INT 21H
MOV DL, LF
MOV AH, 2
INT 21H
RET
Display ENDP
.STARTUP
INVOKE Display, Data1
INVOKE Display, -123456789
.EXIT 0
END
例10.8 编写程序,它能把字类型变量的数值以二、八进制或十六进制形式输出出来。若该数值为负数,则需要输出负号"-",否则,不输出符号。
例10.10 编写一个程序,它能把用键盘输入的字符串转化成相应的数值。具体功能如下:
1、 输入的数据字符串可以带正、负符号,如:1234、+1234或-1234;
2、 字符串的最后一个字符表示数据的进制,默认的进制为十进制,如:1234H表示十六进制数1234,1234为十进制数;
3、 对于任何进制的数据,当遇到一个非进制范围内的字符时,则显示出错信息,并以数值为其转换结果来结束该类型转换过程。
解:
10.4 文件操作程序
有关目录和顺序文件的操作在第8.3.6节中已有介绍和举例,本节主要介绍对记录文件的读写方法。记录文件是指文件中的每个分量是一个结构的文件,如:Fox系列数据库管理系统中的DBF文件,该文件除了文件头是由记录文件的整体信息和各字段描述信息之外,文件的主体内容就是由同一个结构组成的。
下面通过二个例子来介绍记录文件的读写方法。
例10.11 假设有一个简单的学生结构类型student,其包括:学号、姓名和年龄等信息,要求编写一个程序,该程序接受从键盘输入的学生记录信息,并把它们保存在文件students.dat之中。
解:
.MODEL SMALL, C
.486
student STRUCT
id DW ?
sname DB 10 DUP(?)
age DB ?
student ENDS
.DATA
fname
DB "Students.dat",0
msg1
DB "Id:$"
msg2
DB "Name:$"
msg3
DB "Age:$"
msg4
DB "Continue?$"
msg5
DB "Fail to create file$"
CRLF
DB 0AH, 0DH, "$"
buff
DB ?, ?, 11 DUP(?)
peason
STUDENT <>
.CODE
DispMsg PROC USES AX DX, Msg:PTR BYTE ;显示字符串Msg
…… ;参见例10.7
DispMsg ENDP
;程序功能:把字符串Data转化成数值,不考虑负数。当遇到非法字符时,则结束转换操作;
;入口参数:Data为字符串的首地址,Len为该字符串的长度;
;出口参数:数值存放在AX中。
GetData PROC USES BX CX SI, Len:BYTE, Data:PTR BYPE
XOR CX, CX
MOV CL, Len
MOV SI, Data
XOR AX, AX
XOR BX, BX
.REPEAT
MOV
BL, [SI]
SUB
BL, '0'
.BREAK .IF BL<0 || BL>9
;判断当前数值是否在0~9之间
IMUL
AX, 10
ADD
AX, BX
INC
SI
.UNTILCXZ
RET
GetData ENDP
;程序功能:读取指定长度的字符串,在输入前,显示有关输入内容的提示信息;
;入口参数:读入字符串的长度为Len,提示信息的首地址为MSG;
;出口参数:读入信息(字符串)存放缓冲区buff中。
GetInfo PROC USES AX DX, Len:BYTE, Msg:PTR BYTE
INVOKE DispMsg, Msg ;显示提示信息
MOV AL, Len
MOV buff, AL
MOV AH, 0AH
LEA DX, buff
INT 21H
INVOKE DispMsg, ADDR CRLF ;显示回车、换行
RET
GetInfo ENDP
.STARTUP
MOV AX, DS
MOV ES, AX
LEA DX, fname
MOV CX, 20H
MOV AH, 3CH
INT 21H ;创建文件
.IF CARRY? ;若创建失败,则显示失败信息
INVOKE DispMsg, ADDR msg5
JMP over
.ENDIF
MOV BX, AX ;把句柄存入BX,为后面使用作准备
again:
INVOKE DispMsg, ADDR CRLF ;显示回车、换行
INVOKE GetInfo, 5, ADDR msg1 ;读取学号(假定学号为4位整数)
INVOKE GetData, 4, ADDR buff+2 ;把学号字符串转化成数值
MOV peason.id, AX ;把数值型学号存入学号字段
INVOKE GetInfo, 11, ADDR msg2 ;读取姓名(假定姓名为10个字符)
MOV CX, 10
MOV AL, ' '
LEA DI, peason.sname
REP STOSB ;先置姓名字段为10个空格
MOV CL, buff+1
MOV SI, OFFSET buff+2
LEA DI, peason.sname
REP MOVSB ;把输入的姓名存入姓名字段
INVOKE GetInfo, 3, ADDR msg3 ;读取年龄(假定年龄为2位整数)
INVOKE GetData, 2, ADDR buff+2 ;把年龄字符串转化成数值
MOV peason.age, AL ;把数值型年龄存入年龄字段
MOV CX, SIZE peason
LEA DX, peason
MOV AH, 40H
INT 21H ;把学生记录写入文件
INVOKE DispMsg, ADDR msg4 ;提示是否继续输入
MOV AH, 1
INT 21H
AND AL, 0DFH
CMP AL, 'Y'
JZ again ;若按y或Y,则继续输入
MOV AH, 3EH
INT 21H
over:
.EXIT 0
END
例10.12 编写一个程序显示由例10.11建立的记录文件students.dat中的学生信息。
解:
.MODEL SMALL,C
student STRUCT
id DW ?
sname DB 10 DUP(?)
age DB ?
student ENDS
.DATA
fname
DB "Students.dat",0
id1
DB "Id:", 4 dup(?), 0dh, 0ah, "$"
name1
DB "Name:", 10 dup(' '), 0dh, 0ah, "$"
age1
DB "Age:", 2 dup(?), 0dh, 0ah, "$"
msg1
DB "Fail to open file$"
peason
student <>
.CODE
DispMsg PROC USES AX DX, Msg:PTR BYTE ;显示字符串Msg
…… ;参见例10.7
DispMsg ENDP
;程序功能:把数据Data转换成长度为Len的字符串;
;入口参数:待转换数据Data,转换成字符串的长度为Len,存放字符串的首地址为PStr;
;出口参数:读入信息(字符串)存放缓冲区buff中。
GetStr PROC USES AX CX DX DI, Data:WORD, Len:WORD, PStr:PTR BYTE
MOV CX, Len
MOV DI, PStr
MOV AL, ' '
REP STOSB ;把存放字符串的缓冲区填充为空格
MOV DI, PStr
ADD DI, Len
DEC DI ;确定最后一个字符在缓冲区中的位置
MOV AX, Data
MOV CX, 10
.REPEAT
XOR DX, DX
IDIV CX ;除10,从低位向高位求得每一位
ADD DL, '0' ;把余数转变成字符,然后存放目标单元
MOV [DI], DL
DEC DI
.UNTIL AX==0
RET
GetStr ENDP
.STARTUP
MOV AX, DS
MOV ES, AX
LEA DX, fname
MOV AL, 0H
MOV AH, 3DH
INT 21H ;以“只读”方式打开指定的文件
.IF CARRY? ;若创建失败,则显示失败信息
INVOKE DispMsg, ADDR msg1
JMP over
.ENDIF
MOV BX, AX ;把句柄存入BX,为后面使用作准备
again:
MOV CX, SIZE peason
LEA DX, peason
MOV AH, 3FH
INT 21H ;从文件中读出一个记录
.IF CARRY? || AX==0 ;若读记录出错或遇到文件尾,结束
JMP
close
.ENDIF
INVOKE GetStr, peason.id, 4, ADDR Id1+3 ;把“学号”转换成字符串
INVOKE DispMsg, ADDR Id1 ;显示“学号”字符串
MOV CX, 10
LEA SI, peason.sname
LEA DI, Name1+5
REP MOVSB ;把“姓名”转移到显示区
INVOKE DispMsg, ADDR Name1 ;显示“姓名”字符串
INVOKE Getstr, peason.age, 2, ADDR Age1+4 ;把“年龄”转换成字符串
INVOKE Dispmsg, ADDR Age1 ;显示“年龄”字符串
JMP again
close:
MOV AH, 3EH
INT 21H ;关闭当前打开的文件
over:
.EXIT 0
END
从例10.11和10.12,我们不难掌握记录文件的读写方法。有兴趣的读者,还可以利用文件指针的定位来指定读写某个具体的记录。
10.5 动态数据的编程
动态数据结构是一种常用的数据结构,在事先不知道所处理数据容量的情况,用动态数据是一种行之有效的方法,也为许多C语言程序员所采用。在汇编语言中,我们也可以采用动态数据的方式来存储数据,并进行链表的遍历。
为了使读者尽快理解本例的功能,我们把与之相似功能的C语言程序书写如下:
#include <stdio.h>
#include <alloc.h>
struct link {
int data;
struct link *next;
};
void main( )
{struct link *head=NULL, *temp, *pt;
int i;
for (i = 20; i > 0; i--) {
;生成20个结点的链表
temp = (struct link *)calloc(1,sizeof(struct link));
;申请一个结点的空间
if (temp == NULL) break;
;若分配内存失败
temp->data = i;
temp->next = NULL;
if (head == NULL) head = temp;
else pt->next = temp;
pt = temp;
}
while (head != NULL) {
;遍历结点并输出其数据字段
printf("%d\n",head->data);
pt = head; head = head->next; free(pt);
}
}
例10.13 编写一个程序用动态链表存储20,19,……,1,并用遍历链表的方法来显示每个结点的数值。
例10.13 编写一个程序用动态链表存储20,19,……,1,并用遍历链表的方法来显示每个结点的数值。
解:为了便于理解本例程序的执行过程和所构成的动态链表,我们把该链表的构成过程表示成图10.1所示。
图10.1 动态链表数据结构示意图
.MODEL SMALL, C
.DATA
Head
DW 0 ;链表的头指针,初值为空
PT
DW ? ;临时链表指针:当前的链表尾
Buff
DB ?, ?, "$" ;存放输出结果的缓冲区
CRLF
DB 0DH, 0AH, "$" ;回车、换行信息
.CODE
DispMsg PROC USES AX DX, Msg:PTR BYTE ;显示字符串Msg
…… ;参见例10.7
DispMsg ENDP
.STARTUP
MOV CX, 20
.REPEAT
MOV
BX, 1 ;申请内存的字节数=BX×16
MOV
AH, 48H
INT
21H ;申请内存的空间
.BREAK .IF CARRY?
;申请内存失败
MOV
ES, AX ;AX=申请内存的段地址
MOV
WORD PTR ES:[0], CX ;给第一个字赋值
MOV
WORD PTR ES:[2], 0 ;给第二个字置“空”(NULL)
.IF Head==0
MOV Head, ES
;保存链表的头指针
.ELSE
PUSH DS
MOV DS, PT
MOV WORD PTR DS:[2], ES
;把当前申请到的结点链到链表中
POP DS
.ENDIF
MOV
PT, ES ;当前结点向后移
.UNTILCXZ
MOV BX, Head ;从头开始遍历链表
.WHILE (BX!=0)
MOV
ES, BX ;第一个结点的段地址
MOV
AX, ES:[0] ;取第一个结点的数据字段值
MOV
DL, 10
IDIV
DL
ADD
AX, 3030H ;把结点的值转换成字符
LEA
BX, BUFF
MOV
[BX], 2020H ;把字符缓冲区清空
.IF AL>30H
;若十位有非零值,则存储其字符
MOV [BX], AL
INC BX
.ENDIF
MOV
[BX], AH ;存储个位字符
INVOKE
DispMsg, ADDR Buff ;显示结点数据的字符串
INVOKE
DispMsg, ADDR CRLF ;显示回车、换行
MOV
BX, ES:[2] ;BX=下一个结点的段地址
MOV
AH, 49H ;当前结点的段地址已在ES中
INT
21H ;释放当前结点所占的空间
.ENDW
.EXIT 0
END
10.6 COM文件的编程
COM文件和EXE文件都是可执行文件,最典型的COM文件是Command.COM。COM文件的主要特点如下:
1、COM文件只有一个段,其字节数不会超过64K;
2、当操作系统装入COM文件时,四个段寄存器(CS、DS、ES和SS)都 用PSP的段值来初始化;
3、必须用伪指令ORG 100H来说明空出前256个字节。
例10.14 编写一个显示字符串“Hello”的COM类型的程序。
解:
CSEG SEGMENT 'CODE'
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -