
本文共 3561 字,大约阅读时间需要 11 分钟。
一、问题说明:
输入一个十六进制的多位数,将其在程序中转换为十进制的数据输出。
二、思路讲解:
和二进制、八进制、十进制相比,十六进制较为特殊,因为其数据构成含有字母(a~f或A~F);在处理数据时会带来其他进制转换所没有的麻烦!为了解决这个问题,我们需要对于输入的数据(位于寄存器al中)进行ASCII值的筛选判断,以确定输入的是数字、大写字母、小写字母;还是其他违法数据。
观察ASCII值我们不难发现:a~f > A~F > 0~9。我们在具体判断时可以利用这一点,构成从大到小筛选梯度,可以减少比较的次数!
;判断数据的有效性 ;a~f之间的数据: cmp al,60H ja nextaf;进一步判断 ;A~F之间的数据: cmp al,40H ja nextA;进一步判断 ;0~9之间的数据: cmp al,2FH ja next09;进一步判断 jmp over;都不是,则为违规数据 nextaf: cmp al,67H jb minuscules;确定是a~f之间的数据,转入数据累计阶段 jmp over;否则是违规数据 nextA: cmp al,47H jb majuscule;确定是A~F之间的数据,转入数据累计阶段 jmp over;否则是违规数据 next09: cmp al,3AH jb number;确定是0~9之间的数据,转入数据累计阶段 jmp over;否则是违规数据
再将输入数据(位于寄存器al中)中蕴含的数值剥离出来,针对不同的类型,采用不同的处理:
minuscules:;对于小写字母进行处理 sub al,87;剥离出原始数值 mov dl,al;转移数据 jmp addin;将数据加入bx中 majuscule:;对于大写字母进行处理 sub al,55;剥离出原始数值 mov dl,al;转移数据 jmp addin;将数据加入bx中 number:;对于数字进行处理 sub al,48;剥离出原始数值 mov dl,al;转移数据 jmp addin;将数据加入bx中
其他的地方就没啥了,都是比较常见的操作,我代码中也有详细的注释帮助理解!
如果对于下面使用的多位输出函数——outputdata不是很明白的话;可以点击下面的链接直达我往期详细的介绍!这里就不赘述了!
(👈点它)
三、具体代码:
DATAS SEGMENT CRLF DB 0AH,0DH,"$";回车换行DATAS ENDSSTACKS SEGMENT ;此处输入堆栈段代码STACKS ENDSCODES SEGMENT ASSUME CS:CODES,DS:DATAS,SS:STACKSSTART: MOV AX,DATAS MOV DS,AX call inputdata lea dx,crlf mov ah,9 int 21h mov ax,bx call outputdata MOV AH,4CH INT 21H;出口参数:bx ;接收一个16进制的数据,将其转换成为一个十进制的数据累计在寄存器bx中 inputdata proc push ax;数据入栈,防止丢失 push cx push dx ;对于相关数据进行初始化 mov bx,0;用于记录累计的结果 mov cl,16;用于后续的乘法运算 inputagain:;依次循环输入数据并加以判断 mov ah,1 int 21h;接收数据,并且存在寄存器al中ASCII码的形式 ;判断数据的有效性 ;a~f之间的数据: cmp al,60H ja nextaf;进一步判断 ;A~F之间的数据: cmp al,40H ja nextA;进一步判断 ;0~9之间的数据: cmp al,2FH ja next09;进一步判断 jmp over;都不是,则为违规数据 nextaf: cmp al,67H jb minuscules;确定是a~f之间的数据,转入数据累计阶段 jmp over;否则是违规数据 nextA: cmp al,47H jb majuscule;确定是A~F之间的数据,转入数据累计阶段 jmp over;否则是违规数据 next09: cmp al,3AH jb number;确定是0~9之间的数据,转入数据累计阶段 jmp over;否则是违规数据 minuscules:;对于小写字母进行处理 sub al,87;剥离出原始数值 mov dl,al;转移数据 jmp addin;将数据加入bx中 majuscule:;对于大写字母进行处理 sub al,55;剥离出原始数值 mov dl,al;转移数据 jmp addin;将数据加入bx中 number:;对于数字进行处理 sub al,48;剥离出原始数值 mov dl,al;转移数据 jmp addin;将数据加入bx中 addin:;将数据加入bx中 mov ax,bx mul cl mov dh,0 add ax,dx mov bx,ax jmp inputagain;loopover: pop dx;数据出栈,恢复数值 pop cx pop ax retinputdata endp ;入口参数:ax;多位输出函数,以十进制形式输出存储在ax中的多位数outputdata proc push cx push dx;数据入栈,防止丢失 ;数据初始化 mov ch,0;用于计数 mov cl,10;作为除数separateagain:;数据剥离 cmp ax,0 je outputagain;进入具体输出 div cl;剥离数据,存在ah中 push ax;后续取用前八位 mov ah,0;使得ax与al的值相同,便于下次操作 inc ch;计数加一 jmp separateagain;loop outputagain:;数据输出 cmp ch,0 je inputover;输出结束 pop dx mov dl,dh;获取前八位有用的数据 add dl,48 mov ah,2 int 21h dec ch;计数减一 jmp outputagain;loopinputover: pop dx;数据出栈,恢复数据 pop cx retoutputdata endp CODES ENDS END START
四、运行示例:
五、代码极限:
在写完这个代码之后,我想着写都写完了,看看允许输入的最大值为多少?
对于十六进制数据接收函数——inputdata函数;我们对其分析一下不难发现:限制这个函数的上限在于乘法运算的ax寄存器;更为具体的说是ax寄存器的低八位——寄存器al;因为在8086汇编语言中,乘法运算要将参与乘法的一个因数放置在寄存器al中,运算的结果放置在寄存器ax中。
因此在极限条件下,al存储的数据到达了最大,即255。然后乘上16,将结果放置在寄存器ax中,即255x16=4080。再加上输入的最后一个数值,取最大为F(即15);最终在寄存器ax中存储的最大数值为255x16+15=4085。
但是!输入一个价值 3840 的 f00 数据,它也接收不了!
Why?因为不能只考虑输入,你也要保证输入的数据能输出出来!
对于十进制形式输出多位数函数——outputdata函数;我们对其分析一下不难发现:限制这个函数的上限在于除法运算的ax寄存器(没错,又是它!o(* ̄▽ ̄*)ブ);更为具体的说是ax寄存器的低八位——寄存器al(没错,又是它!o(* ̄▽ ̄*)ブ);因为在8086汇编语言中,我们将被除数放置在寄存器ax中,除完之后的商放置在寄存器al中,余数放置在寄存器ah中;在该程序中对于除法的使用,我们可以发现:放置在ah中的余数是一定不会溢出的,因为最大的就是9;所以只需要管寄存器al就可以了!
因为这是除法,数值会随着运算的进行越变越小,所以我们对第一次进行着重分析;第一次的极限条件就是al为255;ah最大为9;于是乎ax可接受的最大值就是255x10+9=2559(对应十六进制数为:9FF)。
验证一下!
再大一个都不行!譬如:输入9FFH+1H=0a00h就报错了!
综上可得,我们分析了两个板块可以接受的极限值,我们取其中的最小值——2559(9FFH),即为整个程序所能接受的最大输入值!
Ending... ...
发表评论
最新留言
关于作者
