; 本程序在MASMPlus 1.2集成环境下通过编译,经过调试,运行正确。虽不敢说万无一失,但自信无虞;请楼主严格测试,若还有误,本回答作废。
; 题目名称:键盘输入两个10位数以内(位数可变)十六进制数,求和并显示输出
; 题目来源:http://zhidao.baidu.com/question/129269410.html
; 操作说明:输入两个10位数以内(位数可变)十六进制数时,输足10位,自动结束输入;不足10位,按回车键结束输入。
Code Segment
Assume CS:Code,DS:Code
CR equ 000DH
LF equ 000AH
KBBack equ 0008H
; -------------------------------------
; 功能:显示指定地址(Str_Addr)的字符串
; 入口:
; Str_Addr=字符串地址(要求在数据段)
Output MACRO Str_Addr
lea dx,Str_Addr
mov ah,9
int 21h
EndM
; -------------------------------------
; 功能:在当前光标位置显示一个字符
; 入口:dl=要显示的字符
Output_Chr proc Near
push ax
mov ah,02h
int 21h
pop ax
ret
Output_Chr Endp
; -------------------------------------
; 功能:显示、输出一个回车、换行
Output_CTLF proc Near
push ax
push dx
mov ah,02h
mov dl,0dh
int 21h
mov dl,0ah
int 21h
pop dx
pop ax
ret
Output_CTLF Endp
; -------------------------------------
; 功能:取光标位置
; 入口:无
; 出口:DH=行号,DL=列号
GetCursor Proc Near
PUSH DS
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH CS
POP DS
XOR BX,BX
MOV AH,3
INT 10H
MOV Cursor_Row,DH
MOV Cursor_Col,DL
POP DX
POP CX
POP BX
POP AX
POP DS
RET
Cursor_Row DB ?
Cursor_Col DB ?
GetCursor EndP
; -------------------------------------
; 功能:置光标位置
; 入口:Cursor_Row=行坐标; Cursor_Col: 列坐标)
SetCursor Proc Near
PUSH DS
PUSH DX
PUSH CX
PUSH BX
PUSH AX
PUSH CS
POP DS
MOV DH,Cursor_Row
MOV DL,Cursor_Col
XOR BX,BX
MOV AH,2
INT 10H
POP AX
POP BX
POP CX
POP DX
POP DS
RET
SetCursor EndP
; -------------------------------------
; 功能:键盘输入一个指定位数(N)的十六进制数字,保存在指定的存储单元
; 输足N位的,自动结束输入;不足N位的,回车结束输入。
; 入口:@@Hexadec=数字位数,ds:di=输入数据保存地址
; 出口:保存在指定的存储单元
Input_Hex Proc Near
push es
push di
push cx
push ax
push ds
pop es
mov cx,cs:@@Hexadec ;十六进制数位数
cld
push cx
xor al,al
rep stosb ;数据缓冲区清零
pop cx
dec di
@@Input_Hex: call GetCursor ;取光标位置
mov ah,1 ;从键盘接受一个字符
int 21h
cmp al,CR ;回车?已经键入的十六进制字符不足N位
jz @@Return_Hex
cmp al,KBBack ;回空键?
jz @@KB_Back ;是,重新输入
cmp al,'0' ;低于数字'0'?
jb @@KBBack ;是,重新输入
cmp al,'9';低于或等于数字'9'?
jbe @@Convert_Bin ;是,转去转换成二进制数
and al,0dfh ;对高于数字'9'的字符视为字母并转换成大写,以便判断是否是A~F之间的字母
cmp al,'A' ;低于字母'A'?
jb @@KBBack ;是,重新输入
cmp al,'F' ;高于字母'F'?
ja @@KBBack ;高于字母'F',重新输入
sub al,7 ;使低4位等于对应字母的十六进制值
@@Convert_Bin: and al,0fh ;转换成二进制数
push ax ;入栈保存
loop @@Input_Hex ;接受下一个数字
@@Return_Hex: mov ax,cx
mov cx,cs:@@Hexadec
sub cx,ax
jcxz @@Return_pop
std
@Reverse_Order:pop ax
stosb ;保存
loop @Reverse_Order
@@Return_pop: pop ax
pop cx
pop di
pop es
ret
@@KB_Back: cmp cx,cs:@@Hexadec ;十六进制数位数
jz @@Input_Hex
inc cx
dec di
dec Cursor_Col
@@KBBack: call SetCursor ;置光标位置
jmp @@Input_Hex
@@Hexadec dw ? ;数字位数
Input_Hex EndP
; -------------------------------------
; 功能:将AL中的低4位二进制数转换成十六进制显示的ASCII码
; 入口:AL
; 出口:AL=转换后的ASCII码
AL_ASCII Proc Near
cmp al,10 ;AL<10?
jb @@To_ASCII ;AL<10,按数字处理
add al,7 ;AL>=10,按大写字母处理
@@To_ASCII: add al,'0' ;转换成相应的数字或大写字母
ret
AL_ASCII EndP
; -------------------------------------
; 功能:键盘输入一个字符,若输入的是'y'或'n'(不分大小写),则显示并返回
; 入口:无
; 出口:若输入的是'y',进位标志置位;若输入的是'n',进位标志复位。
Yes_or_No proc Near
push dx
push ax
@@Input_Chr: mov ah,7 ;不带回显的键盘输入
int 21h
mov dl,al
and al,0dfh
cmp al,'Y'
jnz $+5
stc
jmp $+7
cmp al,'N'
jnz @@Input_Chr
clc
mov ah,2
int 21h
pop ax
pop dx
ret
Yes_or_No Endp
; -------------------------------------
N equ 10 ;数据位数
Summand db N dup(?) ;被加数
Addend db N dup(?) ;加数
Sum db N+1 dup(?) ;和
Prompt_Str1 db 'Please input the summand:$' ;“输入被加数”提示信息
Prompt_Str2 db 13,10,'Please input the addend:$' ;“输入加数”提示信息
Prompt_Str3 db 13,10,'The sum:$' ;“显示相加之和”提示信息
Prompt_Str4 db 13,10,13,10,'Do you want to continue(y/n)?$' ;“继续做加法?”提示信息
Press_Key db 7,13,10,13,10,'The complated. Press any key to exit...$'
; -------------------------------------
Start: push cs
pop ds
push cs
pop es
mov @@Hexadec,10 ;数字位数
Addition_Hex: lea di,Sum ;相加和存放地址
mov cx,N+1
xor al,al
cld
rep stosb ;相加之和初始值清零
Output Prompt_Str1 ;提示输入被加数
lea di,Summand ;被加数存放地址
call Input_Hex ;键盘输入一个指定位数(N)的十六进制数字,保存在指定的存储单元
Output Prompt_Str2 ;提示输入加数
lea di,Addend ;加数存放地址
call Input_Hex
mov si,9 ;个位数下标
lea di,Sum[10] ;相加之和个位数存放地址
mov cx,10 ;数据位数
std
clc ;进位标志位复位
Addition: mov al,Summand[si] ;读入一位被加数
adc al,Addend[si] ;加上加数
push cx
xor ah,ah
mov cx,4
shl ax,cl ;左移4位,把进位标志位移到AH
shr al,cl ;右移4位,把AL的低4位移回
pop cx
stosb ;保存相加结果
rcr ah,1 ;带进位循环右移1位,把进位结果移至标志位
dec si
loop Addition
mov al,ah
rcl al,1 ;把进位标志移入AL
test al,al
jz $+3
stosb ;保存最高位进位
Output Prompt_Str3 ;提示显示相加和
mov cx,N+1
lea di,Sum ;相加和存放地址
xor al,al
cld
repz scasb ;扫描相加和最高有效位
dec di
inc cx
mov si,di ;相加和最高有效位地址
@@Output_Data: lodsb ;读入1位相加和结果
call AL_ASCII ;将AL中的低4位二进制数转换成十六进制显示的ASCII码
mov dl,al
call Output_Chr ;显示一个字符
loop @@Output_Data
Output Prompt_Str4 ;提示是否继续做十六进制加法
call Yes_or_No ;键盘输入一个字符,若输入的是'y'或'n'(不分大小写),则显示并返回
call Output_CTLF ;显示、输出一个回车、换行
call Output_CTLF
jc Addition_Hex
; -------------------------------------
Exit_Proc: Output Press_Key ;提示操作完成,按任意键结束程序
mov ah,1
int 21h
mov ah,4ch ;结束程序
int 21h
Code ENDS
END Start ;编译到此结束
我写的有点长,经验证,运行无误。
代码贴在:任意两个10位以内十六进制数求和
http://tieba.baidu.com/f?kz=681706003
如是能用的,请顶一下。
为了方便修改,新代码直接贴在我的百度空间。
新代码添加了无输入处理和清除前导空格指令。
经验证,无楼主提到的‘1111111111+1111111111=42222222222’
的BUG,显示运算结果准确。
附言:21H的10号(0AH)功能,无法滤除:G~Z,所以不能用;
汤旺河边 错在: rcl al,1 ;把进位标志移入AL.
MOVSB
的英文是
move
string
byte,意思是搬移一个字节,它是把
DS:SI
所指位址的一个位元组搬移到
ES:DI
所指的位址上,搬移后原来的内容不变,但是原来
ES:DI
所指的内容会被覆盖而且在搬移之后
SI
和
DI
会自动地址向下一个要搬移的位址。
一般而言,通常程序设计师只搬一个字节,通常都会重复很多次,如果要重复的话,就得把重复次数先存储在
CX
寄存器,并在
MOVSB
之前加上
REP
指令。
宏和子程序都是为了简化源程序的编写,提高程序的可维护性,但是它们二者之间存在着以下本质的区别:
1、在源程序中,通过书写宏名来引用宏,而子程序是通过CALL指令来调用;
2、汇编程序对宏通过宏扩展来加入其定义体,宏引用多少次,就相应扩展多少次,所以,引用宏不会缩短目标程序;而子程序代码在目标程序中只出现一次,调用子程序是执行同一程序段,因此,目标程序也得到相应的简化;
3、宏引用时,参数是通过“实参”替换“形参”的方式来实现传递的,参数形式灵活多样,而子程序调用时,参数是通过寄存器、堆栈或约定存储单元进行传递的;
4、宏引用语句扩展后,目标程序中就不再有宏引用语句,运行时,不会有额外的时间开销,而子程序的调用在目标程序中仍存在,子程序的调用和返回均需要时间。
mov
bx,offset
data
mov
al,0
mov
cx,100
next:
mov
[bx],al
inc
bx
loop
next
后面的自己动手解决吧!
偷懒可是不好的行为,很少有高手愿意来做这种没有技术含量的书本知识了。
再说全是书上的概念,有必要发出来么。
自己翻翻书不就完了。迎难而上,方显男儿本色。
DATAS SEGMENT
STR1 DB 'The first number a is(eight byte):$'
STR2 DB 'The second number b is(eight byte):$'
STR3 DB 'The answer of the a+b=$'
D1 DB 02FH,03FH,04FH,02FH,02FH,02FH,0FH,0H ;预设要相加的两个八字节数,可任意设置
D2 DB 0H,0F2H,0F2H,0F2H,0F4H,0F4H,0F4H,0H
D3 DB 100 DUP(0)
DATAS ENDS
STACK SEGMENT STACK 'STACK'
DB 100 DUP(?)
STACK ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACK
MAIN PROC FAR
START:
PUSH DS
XOR AX,AX
PUSH AX
MOV AX,DATAS
MOV DS,AX
MOV DX,OFFSET STR1 ;输出第一个八字节数
MOV AH,9
INT 21H
LEA DI,D1 ;因为D1中低位在前,高位在后,所以输出D1要倒着输出
ADD DI,7
MOV CX,8
CALL XS
MOV DX,0AH ;回车换行
MOV AH,2
INT 21H
MOV DX,0DH
MOV AH,2
INT 21H
MOV DX,OFFSET STR2 ;同理,输出D2
MOV AH,9
INT 21H
LEA DI,D2
ADD DI,7
MOV CX,8
CALL XS
MOV DX,0AH ;回车换行
MOV AH,2
INT 21H
MOV DX,0DH
MOV AH,2
INT 21H
MOV DX,OFFSET STR3
MOV AH,9
INT 21H
MOV SI,OFFSET D1 ;调用XJ子程序作八字结数相加
MOV DI,OFFSET D2
MOV BX,OFFSET D3
MOV CX,4
CALL XJ
JNC L1
MOV [BX],1 ;CF=1,最高位置1
L1:LEA DI,D3
ADD DI,8
MOV CX,9
CALL XS ;输出相加的结果
RET
MAIN ENDP
MOV DL, 0DH
MOV AH, 2H
INT 21H
MOV DL, 0AH
MOV AH, 02H
INT 21H
XJ PROC
CLC
AA:MOV AX,[SI] ;用循环实现八字节相加,两字节两字节进行
ADC AX,[DI]
MOV [BX],AX
PUSHF
ADD SI,2
ADD DI,2
ADD BX,2
POPF
LOOP AA
RET
XJ ENDP
XS PROC
LP2:MOV AL,[DI]
MOV BL,AL
PUSH CX
MOV CL,4
SHR AL,CL ;右移4位
CALL PP ;第一次调用输出每个字节的高4位
MOV AL,BL
CALL PP ;第二次调用输出每个字节的低4位
POP CX
DEC DI
LOOP LP2 ;循环分别输出结果的9个字节
RET
XS ENDP
PP PROC
AND AL,0FH ;取AL中的低4位
CMP AL,10 ;比较低4位与10的大小
JB S ;小于,则直接输出低4位
ADD AL,7 ;否则加7后再输出
S:ADD AL,30H
MOV DL,AL
MOV AH,2
INT 21H
RET
PP ENDP
MOV AH,4CH
INT 21H
CODES ENDS
END START
希望能够帮到你!(*^__^*) 嘻嘻……