题目描述
输入一串十进制数,需要判断是否为数字,并将其转化成二进制和十六进制输出。
代码:
二进制:
;description
data SEGMENT
data ENDS
;description
stack SEGMENT
stack ENDS
;description
code SEGMENT
ASSUME CS:CODE, DS:DATA, SS:STACK
start:
mov ax,data
mov ds,ax
xor dx,dx
begin:
mov ah,1h
int 21h
cmp al,13
jz next
cmp al,39h
ja begin
cmp al,30h
jb begin
mov bx,dx
mov cx,3
shl dx,cl
shl bx,1
add dx,bx
and ax,0FFh
sub al,30h
add dx,ax
jmp begin
next:
;已经得到了,在dx中
mov bx,dx
mov cx,16
thorw:
dec cx
shl bx,1
jc ok1
jmp thorw
ok1:
mov dl,31h
mov ah,2
int 21h
ok2:
shl bx,1
jc print1
mov dl,30h
mov ah,2
int 21h
jmp next2
print1:
mov dl,31h
mov ah,2
int 21h
jmp next2
next2:
loop ok2
mov ah,4ch
int 21h
code ENDS
end start
十六进制:
;description
data SEGMENT
data ENDS
;description
stack SEGMENT
stack ENDS
;description
code SEGMENT
ASSUME CS:CODE, DS:DATA, SS:STACK
HTOA PROC
AND AL,0FH
CMP AL,10
JC HTOA1
ADD AL,7
HTOA1:
ADD AL,30H
RET
HTOA ENDP
main PROC
start:
mov ax,data
mov ds,ax
xor dx,dx
begin:
mov ah,1h
int 21h
cmp al,13
jz next
cmp al,39h
ja begin
cmp al,30h
jb begin
mov bx,dx
mov cx,3
shl dx,cl
shl bx,1
add dx,bx
and ax,0FFh
sub al,30h
add dx,ax
jmp begin
next:
;已经得到了,在dx中
mov cx,4
loop1:
push cx
mov cl,4
mov ax,dx
shl dx,cl
and ax,0f000h
mov cl,12
shr ax,cl
pop cx
call htoa
push dx
mov dl,al
mov ah,2
int 21h
pop dx
loop loop1
mov ah,4ch
int 21h
RET
main ENDP
code ENDS
end start
题目分析
判断数字
首先我们需要将输入进行筛选,并且因为是串行输入,我们还需要整合出最终的结果。
我的想法是每一个输入都进行一个判断,如果是回车(ASCII为13),就转出,证明输入结束;
如果大于39h(9 的ASCII)或者小于30h(0 的ASCII)就直接进入下一个循环。
如果是数字,将当前的数值乘十,然后加上输入的数据,继续循环。
问题:
- 这里采用dx寄存器,所以如果输入太大其实会爆掉,但是为了简化问题,才这样做的。
- 我们实际上的读入为ASCII值,在加上的过程中还需要减去30h。(这里的30h表示十六进制数)
- 最开始的清零操作我采取的是xor(异或),这样比直接move要快一些。
所以我们的实现是这样的:
ja、jb这些跳转指令在这篇博客,shl、shr这样的位移指令在这篇博客,右侧目录快速查找。
二进制输出
十进制转其他的进制,最简单的办法其实就是直接进行除法,但是这样会造成我们每一次得到的数据是反着的,需要进行压栈出栈不好处理;另外这样实现也十分麻烦。
这里我们采取的是左移位方式,通过每一次移动一位到CF标志位,然后通过跳转指令来进行判断。
(另外一个思路是SF位,也是使用对应的跳转指令)
二进制数一共是16位,如果前面很多个0就不好看,所以我们利用一个循环将前面的0吃掉。
此时我们的数据在dx寄存器中。(dx要输出,所以又放在bx中)
throw循环就是将SF为零的部分去掉。
注意到我们有一个ok1和2(命名规范就不要吐槽了),这是因为第一个跳出循环的一定为SF = 1,所以我们需要先进行输出。
十六进制输出
这个就不能一次移动1位了,我采取的是先复制,然后一次移动四位。
内容还是在dx中,我们将其复制到ax中,然后取最高的四位,然后移动到dl第四位,这样数据顺序就是正确的。(源码中有一个and 0f000h,其实是没必要的)
对于一个在al低四位的十六进制数,我这里有一个现成的转ASCII子程序htoa,然后将结果打印输出即可。
子程序:
不过这部分我我就没有添加去0功能,确实不太好处理……
运行截图: