当前位置:首页 » 《随便一记》 » 正文

8086汇编:输入输出数字、字符、字符串功能

18 人参与  2023年05月07日 13:37  分类 : 《随便一记》  评论

点击全文阅读


目录

1、输入输出字符串一个示例 2、输入输出字符(数字)2.1 输入输出字符2.2 输入输出数字一个示例 参考资料

前言:初学汇编,可能一时难以习惯这种任何事情都要“亲力亲为”的方式。就拿输入输出来说,高级语言一个函数就可以搞定的事情,在汇编中却不是那么容易的。下面简单介绍下8086汇编输入输出数字和字符串的问题。

1、输入输出字符串

调用21号中断的0ah和09h号功能,可以实现字符串的输入输出
输入字符串,调用0ah号功能
需要注意的是,中断功能的调用大多是有一些约定的,基本上都是通过固定的寄存器传值
拿21h中断的0ah中断来说,这个功能是实现输入字符串的,在此之前首先要提供一个变量存放输入的字符串,这个变量的定义方式是有要求的,如下:

buffer db 50, ?, 50 dup('$')//db表示定义字节大小,第一个50表示想要定义一个50字节大小的变量(申请空间),?表示一个未定义的值,它会记录输入字符串的实际长度,//后面表示连续定义50个字节,用来存放输入的字符串的。至于为什么要定义为'$',这是因为'$'是字符串约定的结尾符号,输出的时候检测到这个符号就代表一个字符串结束。//上面完成了定义一个变量(申请空间),用来存放输入的字符,下面还需要把这个变量的偏移地址给dx寄存器,才可以调用0ah号功能,段地址默认为ds就不需要改了lea dx, buffer;送偏移地址mov ah,0ah;将0ah放入ahint 21h         ;输入字符串功能调用//下面介绍输出字符串功能,相对输入来说输出字符串要简单些/*同样要有一个变量,将变量的地址放入ds:dx,然后调用09h号功能8*/outputstr db 'hello world',0dh,0ah,'$'//0dh,0ah分别是回车换行的ascii码,加到字符串后面表示换到下一行行首,'$'为结束标志lea dx outputstr;送偏移地址mov ah, 09h;将09h放入ahint 21h;输出字符串功能调用

一个示例

下面咱们在dosbox下实验下,代码如下
功能是将输入的字符串在下一行输出

stack segment stackstack endsdata segment    buffer db 50, ?, 50 dup('$')    next_row db 0dh,0ah,'$'data endscode segmentassume cs:code, ds:data, ss:stackstart:  mov ax, data        mov ds, ax        lea dx, buffer          ;输入字符串        mov ah, 0ah        int 21h        lea dx, next_row        ;换行        mov ah, 09h        int 21h        mov dx, offset [buffer+2]      ;输出字符串,注意起始地址        mov ah, 09h        int 21h        mov ah, 4ch        int 21hcode ends        end start

编译、连接、然后执行
在这里插入图片描述

2、输入输出字符(数字)

其实输入输出数字都是通过输入输出字符实现的,准确的说,我们在屏幕上输入输出的只是某个数字(0-9)的ASCII码值(对应30H-39H),而8086的21H号中断提供了输入输出字符的功能。21h号中断要配合ah使用,将功能号放在ah中,再通过int 21h调用

2.1 输入输出字符

1号功能,输入字符

//1号功能,输入字符,输入字符的ascii码放在al中mov ah, 1int 21h//2号功能,输出字符,要输出的字符放在dl中mov dl 31h//31h,即1的ASCII码mov ah 2int 21h

2.2 输入输出数字

其实输入输出数字本质上也就是输入输出字符(串),我们输入或输出的只是ASCII码值,要得到实际的数值,还要经过转换。除此之外,数据的大小(位数)也是受限制的,16位数二进制寄存器能保存的无符号数范围为0~65535,有符号数为-32768 ~ 32767,如果是用八位寄存器,可保存的数范围就更小了。

这里都以有符号的16位为前提讨论
一个比较完善的输入十进制数的处理流程如下:
① 调用21号中断的1号功能输入一个字符
② 判断输入字符的正负,负数,设置标记,正数继续下面步骤
③ 判断输入是否合法(是否为0 - 9),或结束;若非法,提示重新输入,若结束,保存结果,否则继续下一步
④ 将ASCII码值转为数值
⑤ 将已经得到的内容乘以10,加上本次输入的数值
⑥ 转①
流程图如下:
在这里插入图片描述
看起来有点复杂,事实上还好,我们直接上代码

;约定子程序的标号前加proc_前缀;输入子程序,约定输入范围(-32768~32767),结果送到ax input proc near            push bp    mov bp, sp    push bx    push cx    push dxproc_pre_start:    xor ax, ax          ;置零,以免对后面的数据产生影响    xor bx, bx    xor cx, cx    xor dx, dxproc_judge_sign: ;判断符号    mov ah, 1            ;21h-1号功能输入一个字符存入al    int 21h     cmp al, '-'    jne proc_next            ;不是负数,跳到下一步,是负数,设置dx为ffff    mov dx, 0ffffh            jmp proc_digit_inproc_next:    cmp al, 30h         ;判断输入是否合法或结束(键入回车al为odh)    jb proc_unexpected    cmp al, 39h    ja proc_unexpected    sub al, 30h;得到真实数值    shl bx, 1           ;原来数据乘以10,加上al    mov cx, bx    shl bx, 1    shl bx, 1    add bx, cx    add bl, al    adc bh, 0proc_digit_in:    mov ah, 1           ;循环输入,直至结束    int 21h    jmp proc_nextproc_save:    cmp dx, 0ffffh        ;是负数,求补,否则直接保存    jne proc_result_save    neg bxproc_result_save:    mov ax, bx             ;最终结果放入ax    jmp proc_input_doneproc_unexpected:    cmp al, 0dh    je proc_save             ;如输入回车,转到保存结果,否则提示错误信息,重新输入    dispmsg next_row    dispmsg error    jmp proc_pre_startproc_input_done:    pop dx    pop cx     pop bx    pop bp    retinput endp

相比起输入数字,输出数字就好简单些了
一个较为完善的输出数字的处理流程如下:
① 判断符号,正数继续,负数求补并输出一个负号
② 符号扩展为32数,免得除法溢出
③ 采用除10取余法,依次得到个位、十位上的数字,存入堆栈,并判断商是否为0,若为零,输出堆栈中的数据,结束,否则继续除法
流程比较简单,就不上流程图了,咱们直接上代码

;输出子程序,输入参数通过堆栈传递,大小为一个字output proc near            push bp    mov bp, sp    push ax    push bx     push cx    push dx    xor cx, cx    mov bx, [bp+4]          ;将入参放到bx                              test bx, 8000h          ;判断结果是负数还是正数,若为负数,求补码,并输出一个负号    jz proc_nonneg    neg bx    mov dl,'-'    mov ah, 2    int 21hproc_nonneg:     mov ax, bx    cwd                 ;符号扩展为dx.ax,以免除法溢出    mov bx, 10          proc_div_again:    xor dx, dx    div bx              ;除以10取余数,dx:ax / bx = ax......dx    add dl, 30h    push dX              ;结果存入堆栈 ,cx记录除法次数(数据长度)    inc cx    cmp ax, 0           ;商为0,结束,否则循环    jne proc_div_again     proc_digit_out:        pop dx              ;输出    mov ah, 2                 int 21h    loop proc_digit_outproc_output_done:    pop dx    pop cx    pop bx    pop ax    pop bp    ret 2               ;退出子程序,弹出堆栈中主程序给的参数output endp

一个示例

下面是一个示例,功能需求是输入三个有符号16位数字x,y,z;要求求最小值并输出

;csdn@Tao_shimmerstack segment stackstack endsdata segment    x dw ?    y dw ?    z dw ?    min dw ?    inputx db 'please enter the value of x: ','$'    inputy db 'please enter the value of y: ','$'    inputz db 'please enter the value of z: ','$'    outputmin db 'the minimum value of x y z is: ','$'    error db 'input error, please re-enter: ','$'    next_row db 0dh,0ah,'$'data endscode segmentassume cs:code, ds:data, ss:stack;求三个数中最小值的宏,范围(-32768~32767);输入x,y,z,min结果保存到min中min3 macro x,y,z,min             push ax    mov ax, x    cmp ax, y               ;比较x和y,将较小值放入ax    jl xyzmin    mov ax, yxyzmin:     cmp ax, z               ;比较z和min(x,y)将较小值放入ax    jl save_result    mov ax, zsave_result:    mov min, ax    pop axendmdispmsg macro message      ;显示字符串的宏,入参为起始地址    lea dx, message    mov ah, 9    int 21hendm;主程序start:  mov ax, data        mov ds, ax        dispmsg inputx       ;输入提示        call input        mov x, ax ;保存输入        dispmsg inputy        call input        mov y, ax        dispmsg inputz        call input        mov z, ax                min3 x,y,z,min              dispmsg outputmin ;输出提示        push min        call output        mov ah, 4ch        int 21h;约定子程序的标号前加proc_前缀;输入子程序,约定输入范围(-32768~32767),结果送到ax input proc near            push bp    mov bp, sp    push bx    push cx    push dxproc_pre_start:    xor ax, ax          ;置零,以免对后面的数据产生影响    xor bx, bx    xor cx, cx    xor dx, dxproc_judge_sign:    mov ah, 1            ;21h-1号功能输入一个字符存入al    int 21h     cmp al, '-'    jne proc_next            ;不是负数,跳到下一步,是负数,设置dx为ffff    mov dx, 0ffffh            jmp proc_digit_inproc_next:    cmp al, 30h         ;判断输入是否合法或结束(键入回车al为odh)    jb proc_unexpected    cmp al, 39h    ja proc_unexpected    sub al, 30h    shl bx, 1           ;原来数据乘以10,加上al    mov cx, bx    shl bx, 1    shl bx, 1    add bx, cx    add bl, al    adc bh, 0proc_digit_in:    mov ah, 1           ;循环输入,直至结束    int 21h    jmp proc_nextproc_save:    cmp dx, 0ffffh        ;是负数,求补,否则直接保存    jne proc_result_save    neg bxproc_result_save:    mov ax, bx             ;最终结果dx.ax    jmp proc_input_doneproc_unexpected:    cmp al, 0dh    je proc_save             ;如输入回车,转到保存结果,否则提示错误信息,重新输入    dispmsg next_row    dispmsg error    jmp proc_pre_startproc_input_done:    pop dx    pop cx     pop bx    pop bp    retinput endp;输出子程序,输入参数通过堆栈传递,为一个字output proc near            push bp    mov bp, sp    push ax    push bx     push cx    push dx    xor cx, cx    mov bx, [bp+4]          ;将入参放到bx                              test bx, 8000h          ;判断结果是负数还是正数,若为负数,输出一个负号    jz proc_nonneg    neg bx    mov dl,'-'    mov ah, 2    int 21hproc_nonneg:     mov ax, bx    cwd                 ;符号扩展为dx.ax,以免除法溢出    mov bx, 10          proc_div_again:    xor dx, dx    div bx              ;除以10取余数,dx:ax / bx = ax......dx    add dl, 30h    push dX              ;结果存入堆栈 ,cx记录除法次数(数据长度)    inc cx    cmp ax, 0           ;商为0,结束,否则循环    jne proc_div_again     proc_digit_out:        pop dx              ;输出    mov ah, 2                 int 21h    loop proc_digit_outproc_output_done:    pop dx    pop cx    pop bx    pop ax    pop bp    ret 2               ;退出子程序,弹出堆栈中主程序给的参数output endpcode ends    end start

下面是在dosbox下的测试截图
在这里插入图片描述

参考资料

《汇编语言程序设计》第五版 钱晓捷等


点击全文阅读


本文链接:http://zhangshiyu.com/post/61356.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1