本文共 8895 字,大约阅读时间需要 29 分钟。
将一个数据存入AX中,分别以有符号数、二进制、八进制、十六进制的形式输出。
从本质上来讲,计算机可不会管你存的是何种形式的数,存储进来了就只是01的数字串。所以我们以各种各样形式的输出从本质上来说是看这些01串的角度的问题。
当我们以有符号数看待计算机中存储的01串时,最高位就默认成为了符号位,0代表是正数,1代表是负数。
(注:下方代码使用的是方案二)
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 mov ax,123 call symoutput lea dx,crlf mov ah,9 int 21h mov ax,-123 call symoutput MOV AH,4CH INT 21H;有符号数的输出,入口参数为axsymoutput proc push bx;入栈保存 push dx mov bx,ax;保存数据防止后续修改,可直接调用函数 cmp ax,0;比较ax中数字的正负 js negative;负数的输出 jmp positive;正数的输出 negative: mov dl,'-';输出负号 mov ah,2 int 21h neg bx;求补数 call output jmp symoutputover positive: call output symoutputover: pop dx;出栈复原 pop bx retsymoutput endp ;多位输出函数,入口参数为bxoutput proc push ax;数据入栈区 push cx push dx ;初始化变量 mov ax,bx;数据放入准备除法 mov cl,10;作为除数 mov ch,0;用于计数便于后续出栈输出 divagain:;除法数字剥离部分 cmp ax,0;判断是否已经除尽 je divover inc ch;计数器加1 div cl push ax;入栈,提取的时候取用ah部分,存储余数(低位优先) mov ah,0;调整ax jmp divagain;再次除法剥离数字 divover:;出栈输出部分 cmp ch,0;判断数字是否已经出尽 je outputover pop ax;取用ah部分 mov dl,ah;输出部分 add dl,48 mov ah,2 int 21h dec ch jmp divover outputover:;收尾部分 pop dx pop cx pop ax;数据出栈区 retoutput endpCODES ENDS END START
(注:下方代码使用的是方案一)
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 mov ax,8 call binaryoutput lea dx,crlf mov ah,9 int 21h mov ax,-8 call binaryoutput MOV AH,4CH INT 21H ;二进制形式的输出,入口参数为axbinaryoutput proc push bx;数据入栈,保留数值 push dx mov dh,0;用于计数,总共16次 binaryagain: cmp dh,16 je binaryover;输出结束,到达函数末端 rol ax,1;移动一位 mov bx,ax;数值保留 and ax,0001h;剥离出最后一位 mov dl,al;用于输出 add dl,48 mov ah,2 int 21h inc dh;计数加一 mov ax,bx;数值恢复 jmp binaryagain;再来一次 binaryover: pop dx;数据出栈,数值还原 pop bx retbinaryoutput endpCODES ENDS END START
(注:下方代码使用的是方案二)
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 mov ax,8 call octaloutput lea dx,crlf mov ah,9 int 21h mov ax,-8 call octaloutput MOV AH,4CH INT 21H ;八进制形式的输出,入口参数为axoctaloutput proc push bx;数据入栈,数值保留 push cx push dx ;无法完整切割,所以换一种策略,循环除法 mov cl,8;作为除数 mov ch,0;作为计数器 octalagain:;数据剥离板块 cmp ax,0 je octalout;存数结束,进入输出阶段 inc ch;计数器加一 div cl;运行除法剥离数据 mov dl,ah mov dh,0 push dx;数据入栈,后续取用dl直接输出 mov ah,0;使得ax与al值统一 jmp octalagain;loop octalout:;数据输出板块 cmp ch,0 je octalover;输出完毕 dec ch pop dx;取出数据 add dl,48 mov ah,2 int 21h jmp octalout;loop octalover: pop dx;数据出栈,数值还原 pop cx pop bx retoctaloutput endpCODES ENDS END START
本想着方案二做完算了,担心老师不满意(显示Divide error!),所以又整了个方案一的代码!
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 mov ax,8;正数测试 call octaloutput lea dx,crlf;输出回车换行 mov ah,9 int 21h mov ax,-8;负数测试 call octaloutput MOV AH,4CH INT 21H ;八进制形式的输出,入口参数为axoctaloutput proc push bx;数据入栈,数值保留 push cx push dx ;最高一位单独输出处理 rol ax,1;移动一位 mov bx,ax;保留数值 and al,01h;剥离最后一位数据 mov dl,al;准备输出 add dl,48 mov ah,2 int 21h mov ax,bx;恢复数值 ;对后续的15位进行处理,15除3等于5 mov dh,0;计数5次,留下最后一位单独处理octalagain: cmp dh,5 je octalover;循环结束,进入收尾工作 inc dh;计数加一 mov cl,3;作为移位位数 rol ax,cl;移动最高三位 mov bx,ax;保留ax的值防止修改 and al,07h;剥离后三位数据 mov dl,al;准备输出 add dl,48 mov ah,2 int 21h mov ax,bx;恢复ax的保留数值 jmp octalagain;loopoctalover: pop dx;数据出栈,数值还原 pop cx pop bx retoctaloutput endpCODES ENDS END START
(注:下方代码使用的是方案一)
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 mov ax,8 call hexadecimaloutput lea dx,crlf mov ah,9 int 21h mov ax,-8 call hexadecimaloutput MOV AH,4CH INT 21H ;十六进制形式的输出,入口参数为axhexadecimaloutput proc push bx;数据入栈,数值保留 push cx push dx mov dh,0;用于计数,总共4次 hexadecimalagain: cmp dh,4 je hexadecimalover;循环结束,进行收尾工作 inc dh;计数加一 mov cl,4 rol ax,cl mov cx,ax;数值保留 and ax,0fh;数据剥离后四位 mov dl,al cmp dl,9;区分需要输出数字还是字母 ja alphabet;作为字母输出 add dl,48;作为数字形式的输出 mov ah,2 int 21h mov ax,cx;数据恢复 jmp hexadecimalagain alphabet:;作为字母形式的输出 add dl,55 mov ah,2 int 21h mov ax,cx;数据恢复 jmp hexadecimalagainhexadecimalover: pop dx;数据出栈,数值保留 pop cx pop bx rethexadecimaloutput endpCODES ENDS END START
为什么上面输入负数使用除法就不行了呢?
因为在你输入负数之后,在寄存器ax中是以补码的形式进行存储,所以首位是 1 ,但是计算机可不会管你是不是正负数,进去之后就是01串,此时值就很大。当你进行除法将数据进行剥离的时候,除完之后的结果是放在 ah 和 al 中的,ax 是16位的,但是 ah 和 al 是8位的,所以在上面程序中除完之后的结果放在寄存器 ah 和 al就会溢出,进而报错!
所以建议使用移位进行处理!
DATAS SEGMENT CRLF DB 0AH,0DH,"$";回车换行 string db "The original value was:","$";原本数值输出提示 string1 db "The binary form is:","$";二进制输出提示 string2 db "The octal number system is:","$";八进制输出提示 string3 db "The hexadecimal form is:","$";十六进制输出提示DATAS ENDSSTACKS SEGMENT ;此处输入堆栈段代码STACKS ENDSCODES SEGMENT ASSUME CS:CODES,DS:DATAS,SS:STACKSSTART: MOV AX,DATAS MOV DS,AX ;原来有符号数形式的输出 lea dx,string;原本数据的输出提示 mov ah,9 int 21h mov ax,-123 call symoutput lea dx,crlf mov ah,9 int 21h ;二进制形式的输出 lea dx,string1;二进制的输出提示 mov ah,9 int 21h mov ax,-123 call binaryoutput lea dx,crlf mov ah,9 int 21h ;八进制形式的输出 lea dx,string2;八进制的输出提示 mov ah,9 int 21h mov ax,-123 call octaloutput lea dx,crlf mov ah,9 int 21h ;十六进制形式的输出 lea dx,string3;十六进制的输出提示 mov ah,9 int 21h mov ax,-123 call hexadecimaloutput lea dx,crlf mov ah,9 int 21h MOV AH,4CH INT 21H ;二进制形式的输出,入口参数为axbinaryoutput proc push bx;数据入栈,保留数值 push dx mov dh,0;用于计数,总共16次 binaryagain: cmp dh,16 je binaryover;输出结束,到达函数末端 rol ax,1;移动一位 mov bx,ax;数值保留 and ax,0001h;剥离出最后一位 mov dl,al;用于输出 add dl,48 mov ah,2 int 21h inc dh;计数加一 mov ax,bx;数值恢复 jmp binaryagain;再来一次 binaryover: pop dx;数据出栈,数值还原 pop bx retbinaryoutput endp;八进制形式的输出,入口参数为axoctaloutput proc push bx;数据入栈,数值保留 push cx push dx ;最高一位单独输出处理 rol ax,1;移动一位 mov bx,ax;保留数值 and al,01h;剥离最后一位数据 mov dl,al;准备输出 add dl,48 mov ah,2 int 21h mov ax,bx;恢复数值 ;对后续的15位进行处理,15除3等于5 mov dh,0;计数5次,留下最后一位单独处理octalagain: cmp dh,5 je octalover;循环结束,进入收尾工作 inc dh;计数加一 mov cl,3;作为移位位数 rol ax,cl;移动最高三位 mov bx,ax;保留ax的值防止修改 and al,07h;剥离后三位数据 mov dl,al;准备输出 add dl,48 mov ah,2 int 21h mov ax,bx;恢复ax的保留数值 jmp octalagain;loopoctalover: pop dx;数据出栈,数值还原 pop cx pop bx retoctaloutput endp;十六进制形式的输出,入口参数为axhexadecimaloutput proc push bx;数据入栈,数值保留 push cx push dx mov dh,0;用于计数,总共4次 hexadecimalagain: cmp dh,4 je hexadecimalover;循环结束,进行收尾工作 inc dh;计数加一 mov cl,4 rol ax,cl mov cx,ax;数值保留 and ax,0fh;数据剥离后四位 mov dl,al cmp dl,9;区分需要输出数字还是字母 ja alphabet;作为字母输出 add dl,48;作为数字形式的输出 mov ah,2 int 21h mov ax,cx;数据恢复 jmp hexadecimalagain alphabet:;作为字母形式的输出 add dl,55 mov ah,2 int 21h mov ax,cx;数据恢复 jmp hexadecimalagainhexadecimalover: pop dx;数据出栈,数值保留 pop cx pop bx rethexadecimaloutput endp ;有符号数的输出,入口参数为axsymoutput proc push bx;入栈保存 push dx mov bx,ax;保存数据防止后续修改,可直接调用函数 cmp ax,0;比较ax中数字的正负 js negative;负数的输出 jmp positive;正数的输出 negative: mov dl,'-';输出负号 mov ah,2 int 21h neg bx;求补数 call output jmp symoutputover positive: call output symoutputover: pop dx;出栈复原 pop bx retsymoutput endp ;多位输出函数,入口参数为bxoutput proc push ax;数据入栈区 push cx push dx ;初始化变量 mov ax,bx;数据放入准备除法 mov cl,10;作为除数 mov ch,0;用于计数便于后续出栈输出 divagain:;除法数字剥离部分 cmp ax,0;判断是否已经除尽 je divover inc ch;计数器加1 div cl push ax;入栈,提取的时候取用ah部分,存储余数(低位优先) mov ah,0;调整ax jmp divagain;再次除法剥离数字 divover:;出栈输出部分 cmp ch,0;判断数字是否已经出尽 je outputover pop ax;取用ah部分 mov dl,ah;输出部分 add dl,48 mov ah,2 int 21h dec ch jmp divover outputover:;收尾部分 pop dx pop cx pop ax;数据出栈区 retoutput endp CODES ENDS END START
转载地址:http://hlmg.baihongyu.com/