?? 匯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 + -