汇编实验之各种进制之间的转换

时间:2025-02-10 11:55:07

总结:
输入的字符首先要转换为数的形式存在内存中,再进行转换输出。

1、字符转换成数:
①二进制输入:将输入的二进制字符用二进制来表示,即-30h,得到的0/1则是我们想要得到的数,此时0/1存在al的最低一位,即最右边一位,采用逻辑右移SHR指令,将0/1送往CF,再对bx使用带进位的循环左移RCL,则0/1送往bx的最低一位,循环如此,即可实现将二进制的输入在bx中用二进制来表示。
②十六进制输入:将上一次的结果往前推一位,即×16。
③八进制输入:将上一次的结果往前推一位,即×8。
④无符号十进制输入:将上一次的结果往前推一位,即×10。
⑤有符号十进制输入:用cx装载-1表示负数,否则为正数,若是正数和无符号数输入一样,若为负数则要对该数进行求补。

2、转换成进制输出:
①二进制输出:依次左移输出字符,左移16次。
②十六进制输出:用到换码指令,需先把表格的首地址放在BX寄存器中,将相对于表格首地址的偏移量放在AL中,得到的AL就是转换后的地址里的内容,也就是转换后的代码。
③八进制输出:先取bx中存放的二进制的后三位,转换为ASCII码,压栈,后面可输出,然后对bx逻辑右移三位,取后三位,转换为ASCII码压栈,依次直到bx为0。pop bx,可得到对应的八进制数。
④有符号十进制输出:用OR来判断该数为正数还是负数,若为负数,则先输出负号,且对该数进行求补,若为正数则不做改变。

一、二进制与十六进制
1.编写一段程序,从键盘接收一个四位的十六进制数,并在终端上显示与它等值的二进制数。

DATAS SEGMENT
    NUM DW 0
    CRLF DB 0DH,0AH,'$'  
DATAS ENDS

STACKS SEGMENT
    
STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
    MOV AX,DATAS
    MOV DS,AX
    MOV DX,0
    MOV CX,4
    
L:  MOV AH,1
    INT 21H
    CMP AL,40H
    JG L1
    JL L2
    
L1: SUB AL,07H;大写字母多减7,得到0ah...

L2: SUB AL,30H;说明是数字字符要将ASCII码转成对应数字
    
    PUSH AX
    MOV AX,NUM
    MOV BX,16
    MUL BX
    POP BX
    ADC AL,BL
    MOV NUM,AX
    LOOP L;循环4次,使输入的16进制数变成10进制数
    
    LEA DX,CRLF
    MOV AH,9
    INT 21H;换行
    
    MOV CX,16
    MOV BX,NUM
    
L3: MOV DL,31H
    SAL BX,1;左移1位,改变CF
    JC L4;CF为1,输出1
    SUB DL,1;CF为0,所以DL减去1,输出0
           
L4: MOV AH,2
    INT 21H
    LOOP L3 
             
    MOV AH,4CH
    INT 21H
CODES ENDS
    END START

解题思路:将输入的十六进制字符转换为十六进制整数,整数会以二进制形式存在内存中,所以依次左移输出字符即可得到对应二进制数。

二、二进制与八进制
1.编写一个程序,从键盘输入一个不大于16位的2进制数,然后以8进制形式显示出所输入的数。

DATA SEGMENT
    x dw 0ah,0dh,'$'
    InputBuffer db 17,0,17 dup (0)  ;第一个字节为用户定义的最大字符数(0-255);第二个字节是实际输入字符的个数;第三个字节,字符串开始按字节存入缓冲区
    UserInput dw 0

DATA ENDS

CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
    MOV AX,DATA
    MOV DS,AX

    call GetUserInput ;输入子程序
    mov UserInput,ax ;取得输入值16进制,也是2进制
    lea dx,x
    mov ah,9
    int 21h
    mov bx,UserInput ;取得输入值
    mov cl,3 ;移位数
    mov ch,0 ;计数
next:
    mov ax,bx
    and ax,0000000000000111b ;取低3(111),即八进位
    or al,'0' ;转ascii:30H二进制与0-7的二进制相或=30H+0-7.即也可以用ADD AL,30H来表示
    push ax ;保存
    inc ch ;计数
    shr bx,cl ;右移3,即下一位
    or bx,bx ;是否完了
    jnz next ;未
    mov cl,ch ;取得计数
    mov ch,0 ;0
next1:
    pop dx ;弹出dl,即将压栈的AX弹出赋值给DX
    mov ah,2 ;印出结果
    int 21h
    loop next1
    mov ah,7 ;暂停
    int 21h
quit:
    MOV AH,4CH ;带返回码结束功能
    INT 21H ;返回系统
;-----------------------
GetUserInput:
    mov dx,offset InputBuffer ;指向输出缓冲
    mov ax,0c0ah ;输入函数,先清空键盘缓冲,mov ah,0ch清除键盘缓冲区,mov al,0ah输入字符到缓冲区
    int 21h
    mov si,offset InputBuffer + 2;字符串开始的第一个字符
    mov cx,0
    mov cl,[si-1] ;取实际输入数
    jcxz GetUserInput ;无输入,测试CX内容为0则转移
    Call GetValue ;取值子程序,ax传回该值,cf=1表示错误,可能输入非数字
    jc GetUserInput ;输入错误,非数字
    ret
;--------------------------------------------------------------------------
;转值子程序,把输入的字符转成16进制(2进制)
;输入:ds:si数字字符串起点,0dh结束
;输出:ax=转换后的16进制值,cf=1表示有非数字字符
GetValue:
    push bx
    push di
    xor bx,bx
    mov di,10
GetV10:;实现将输入的二进制字符转换成二进制形式存在BX中
    lodsb ;指向起点,将由源变址寄存器(此处值si寄存器)指向的数据段中某单元的内容送到AL、AX、EAX中去
    mov ah,0 ;清除
    cmp al,0dh 
    jz Getvx
    cmp al,30H ;输入的不是01则输入错误,置CF=1
    jb Getvy
    cmp al,'1'
    ja Getvy
    sub al,30H ;ascii -> 值
    shr al,1 ; cf=1,1 cf=0,0,逻辑右移
    rcl bx,1 ;一位接一位的旋入bx,带进位的循环左移
    jmp short GetV10
Getvx: mov ax,bx ;ascii转值后由ax转回
       clc ;成功cf=0
       jmp short Getvz
Getvy:
      stc ;错误 cf=1
Getvz:
      pop di
      pop bx
      ret
;------------------------------------
CODE ENDS
END START

解题思路:
①将输入的二进制字符用二进制来表示,即-30h,得到的0/1则是我们想要得到的数,此时0/1存在al的最低一位,即最右边移位,采用逻辑右移SHR指令,将0/1送往CF,再对bx使用带进位的循环左移RCL,则0/1送往bx的最低一位,循环如此,即可实现将二进制的输入在bx中用二进制来表示。
②八进制输出:先取bx中存放的二进制的后三位,转换为ASCII码,压栈,后面可输出,然后对bx逻辑右移三位,取后三位,转换为ASCII码压栈,依次直到bx为0。pop bx,可得到对应的八进制数。

三、二进制与十进制
1.编写一个程序,计算 1 + 2 + 3 + 4 + … + 100的累加和,并把累加和以2进制形式显示出来。(十进制整数转换为二进制输出)
(要使用循环累加方法,不能使用公式S=N*(N+1)/2=50*101=5050)。

DATAS SEGMENT
    sum dw 0  
DATAS ENDS

STACKS SEGMENT
    ;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
    MOV AX,DATAS
    MOV DS,AX
    
    mov ax,0
    mov bx,1
lp1:           ;实现累加和,ax中装总和数
    add ax,bx
    inc bx
    cmp bx,101
    je next
    jmp lp1
next:
    mov cx,16
    mov bx,ax
lp3:
    shl bx,1;逻辑左移指令
    jc lp2   ;进位为1则转移
    mov ah,2
    mov dl,0
    add dl,30h
    int 21h
    dec cx
    cmp cx,0
    je exit
    jmp lp3
lp2: 
    mov ah,2
    mov dl,1
    add dl,30h
    int 21h
    dec cx
    cmp cx,0
    je exit
    jmp lp3
    
exit:MOV AH,4CH
    INT 21H
CODES ENDS
    END START

解题思想:在内存中存在的十进制整数其实是以二进制形式存在,所以直接将数每次逻辑左移一位(左移十六次),根据CF位,选择将1或0放入dl中,进行输出即可。

2.二进制输入,十进制输出。

DATAS SEGMENT
    CRLF DB 0DH,0AH,24H;此处输入数据段代码  
DATAS ENDS

STACKS SEGMENT
    ;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS
MAIN PROC NEAR
    MOV AX,DATAS
    MOV DS,AX
    CALL I2;调用子程序
    CALL D10
    MOV AH,4CH
    INT 21H
MAIN ENDP
I2   PROC NEAR
     PUSH BX;确保不会影响主程序的值
     PUSH CX
     PUSH DX
     PUSH SI
     PUSH DI
     XOR BX,BX;bx清零
     MOV CX,16;cx装载计数
L20:MOV AH,1;一号调用输入字符
    INT 21H
    CMP AL,0DH;输入回车,则不再进行输入字符程序
    JE  L21
    CMP AL,30H;输入的数比0小或比1大,则继续输入字符
    JB L20
    CMP AL,31H
    JA L20
    AND AX,01H  ;完成二进制输入的功能
    SHL BX,1
    ADD BX,AX;bx装的是二进制数
    LOOP L20
L21:MOV AX,BX;把bx装的二进制数送回ax中
    POP DI
    POP SI
    POP DX
    POP CX
    POP BX
    RET
I2   ENDP


D10  PROC NEAR
     PUSH AX
     PUSH BX
     PUSH CX
     PUSH DX
     PUSH SI
     PUSH DI
     MOV BX,AX;二进制数在ax中
     MOV AH,9;9号调用输出字符串,是crlf的字符串
     LEA DX,CRLF;把crlf地址送入dx
     INT 21H
     OR BX,BX;判断是正数还是负数
     JNS L100;符号位s为0即为正数就跳转,否则就输出负号,并且对二进制数求补
     MOV AH,2;二号调用输出单个字符
     MOV DL,"-"
     INT 21H
     NEG BX;对bx求补
L100:MOV AX,BX
     XOR CX,CX;cx清零
     MOV SI,10
L101:XOR DX,DX;dx清零,为了后面装余数
     DIV SI;div已经自动将内存里的进制转成十进制。十进制数除10得到的余数装载在dx中,将余数压入栈然后输出
     PUSH DX
     INC CX
     CMP AX,0;比较ax(商)是否为0,若不为0则继续除10,为0则出栈输出字符
     JNZ L101
L102:POP DX
     MOV AH,2
     ADD DL,30H;数字转换为字符输出
     INT 21H
     LOOP L102
     POP DI
     POP SI
     POP DX
     POP CX
     POP BX
     POP AX
     RET
D10   ENDP
CODES ENDS
    END MAIN

四、八进制与十进制

五、八进制与十六进制
六、十进制与十六进制
1.编写一个程序,从键盘输入一个0~65535之间的10进制无符号数,然后以16进制形式显示出所输入的数。

data    segment
     string     db      0dh
     num        db      4 dup(?),'H$'
     tab        db      '0123456789ABCDEF'
data    ends

code    segment
        assume  cs:code,ds:data
begin:  mov     ax,data
        mov     ds,ax  ;初始化代码段

        xor     bx,bx  ;bx清零
        mov     cx,10  ;进制
next:  ;输入十进制
        mov     ah,1   ;输入字符,存进AL的是字符的ASCII码
        int     21h
        cmp     al,0dh
        jz      conv  ;如果是回车,表示输入结束,转换开始
        push    ax  ;保存输入值,当然还有AH,因为堆栈的存取必须以字为单位
        mov     ax,bx
        mul     cx
        mov     bx,ax  ;将先前的结果向上推一位
        pop     ax  ;取回本次输入
        and     al,0fh  ;屏蔽掉无用位,类SUB AL,30H
        xor     ah,ah  ;高位归零
        add     bx,ax  ;合并本次输入
        jmp     next
conv:   mov     ax,bx  ;开始转换
        mov     ch,4
        lea     bx,tab  ;bx直接定址表
        mov     cl,4
        lea     si,num
lopa:   rol     ax,cl  ;把高4位移到低4位
        push    ax
        and     ax,000fh ;取出低4位
        xlat
        mov     [si],al  ;按地址由低到高的顺序将结果由高到低存放
        inc     si
        pop     ax
        dec     ch
        jnz     lopa
        lea     dx,string;9号调用,先把要输出的字符串首地址的偏移地址存入DX中  /lea dx,num
        mov     ah,9
        int     21h  ;回车换行
        mov     ah,4ch
        int     21h
code    ends
        end     begin

解题思路:
①将输入的字符转换成十进制数形式存放在内存中,将先前的结果往前推一的方法。
②将得到的十进制数转换成十六进制输出,用到换码指令,需先把表格的首地址放在BX寄存器中,将相对于表格首地址的偏移量放在AL中,得到的AL就是转换后的地址里的内容,也就是转换后的代码。