汇编——十六进制输入转换十进制输出(附加输入检测)

题目描述

输入一个最大长度为4的十六进制数,将其转换成10进制输出。
其中我们需要检测十六进制输入的正确性,比如大小写、特殊字符和数字的判断。

解决方式

程序分为两个部分,首先是处理我们的输入,以及通过除法计算十进制数的过程。

data SEGMENT USE16
	
data ENDS
stack SEGMENT USE16
	      db 32 dup(?)
stack ENDS
code SEGMENT USE16
	         ASSUME CS:CODE, DS:DATA, SS:STACK
main PROC
	start:   
	         mov    ax,data
	         mov    ds,ax
	         xor    bx,bx
	         mov    dl,4
	loop1:   
	         cmp    dl,0
	         jz     next
	         mov    ah,1
	         int    21h
	         cmp    al,13
	         jz     next
	;数字
	         cmp    al,30h
	         jb     loop1
	         cmp    al,39h
	         ja     big
	         sub    al,30h
	         dec    dl
	         jmp    fin
	big:     
	         cmp    al,65
	         jb     loop1
	         cmp    al,70
	         ja     small
	         sub    al,37h
	         dec    dl
	         jmp    fin
	small:   
	         cmp    al,97
	         jb     loop1
	         cmp    al,102
	         ja     loop1
	         sub    al,87
	         dec    dl
	fin:     
	         mov    cl,4
	         shl    bx,cl
	         and    ax,0fh
	         add    bx,ax
	         jmp    loop1
	next:    
	         cmp    dl,0
	         jnz    no_need
	         mov    dl,10
	         mov    ah,2
	         int    21h
	         mov    dl,13
	         mov    ah,2
	         int    21h
	no_need: 
	         mov    ax,bx
	         mov    cx,10
	         xor    bx,bx
	turn_in: 
	         xor    dx,dx
	         div    cx
	         push   dx
	         inc    bl
	         cmp    ax,0
	         jz     turn_out
	         jmp    turn_in
	turn_out:
	         pop    dx
	         add    dl,30h
	         mov    ah,2
	         int    21h
	         dec    bl
	         cmp    bl,0
	         jnz    turn_out
	         mov    ah,4ch
	         int    21h
main ENDP
code ENDS
end start
输入(next标号之前)

首先看一下输入部分,我们需要解决四个问题。

  • 输入结束有两个标准,一个是输入满四位,另一个是检测到回车
  • 不论是大小写还是数字,我们都需要读入(记住读入的是ascii,还需要处理一下)
  • 对于其他字符,我们需要跳过,进行下一个循环
  • 如果是需要读入,我们就需要将原来的数据左移四位(乘16),然后加上处理过的输入。

首先,我们将dl作为计数器,每一次循环观测dl是否为0,同时读入一个数据,判断是否为回车(ascii为13)。
然后我们判断一下输入的正确性问题。这里我画出了ascii表中数字和大小写的排列顺序。
在这里插入图片描述
所以我们是这样判断的:
在这里插入图片描述
这就是我们的跳转流程。
(为什么要减这些数,自己查一下ASCII,当增强记忆了)

与其说这个结构是if_else,我倒是感觉更像case,其中的jmp指令就像是break,如果没有break,那么我们就会将下一个分支也执行了,导致出错。

在每一次读入之后,我们说白了其实是将之前的作为高位,然后加入低位。
(比如输入十进制123,我们是先将12左移一位,也就是乘十,然后加三)
这里也一样,不过我们需要bx右移四位(寄存器中为二进制数),然后加上存储在al的值。

另外附上我们的测试案例:(1e23),可以看到BX值正确。
在这里插入图片描述

输出

这里因为是十进制的输出,我们之前还可以通过进制偷懒(指输出二进制或十六进制数),现在是不行了。
这里我们采用每一次除以10,将余数压栈的方式,存储好结果的相反顺序,然后pop到dl,进行输出。

这里先讲一下汇编的乘除法吧。
对于两个二进制数来说,a位乘以b位的,那么结果一定不会大于a+b位。
(2a-1-1和2b-1-1一定小于2a+b-1
我们在除的过程中也是如此,因为bx是16位,我们的除数10为4位,所以我们的结果是不能用al和ah放下的(余数小于等于除数的位数,商小于等于被除数位数减除数位数。)
那么我们还有一种办法,就是将DX:AX作为被除数,将CX作为除数,这样商在AX,余数在DX,就能放下了。
如果是再次除,我们只需要将dx置零。
效果:
在这里插入图片描述
通过这样一个案例,我们知道了选择除法范围也是有考量的,不是怎么方便怎么来的。

turn_in循环就实现了每一次将ax寄存器除以十,商在ax,余数在dx,将dx压栈后清零,再次进行除法。
每一次除法我们都将计数器bl自增,方便出栈使用。
当ax寄存器为0,我们结束循环,进入到输入(turn_out)部分。

turn_out部分我们每一个循环都弹出一个dx,因为dx的余数一定是小于10的,我们直接加30h输出即可。

这里写的不是太好,其实完全可以将bl放在cl中,然后直接loop的。

补充

这部分最重要应该就是跳转逻辑和我们的除法部分。

另外讲解一下no_need标签部分:
因为我们如果是输入满四位,会强制性结束输入,这时就没有我们的回车显示了,所以我加了一个判断来进行换行,看着比较舒服,没别的意思。

然后补充一下自己的十进制输入转二进制/十六进制输出的案例。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值