使用NASM汇编将16位十进制数转换为其他进制数

3

我在使用NASM汇编实现十进制转二进制、八进制和十六进制的转换时遇到了一些问题。以下是我已经完成的大部分代码,我知道它存在一些问题,正在努力修复中。我已经在代码中添加了相关信息的注释。

    %include "io.mac"
    .STACK 100H
    .DATA
    msg1        db "Please enter a positive integer (max 16 bits): ",0
    msg2        db "The binary (base-2) representation of the number is: ",0
    msg3        db "The octal (base-8) representation of the number is: ",0
    msg4        db "The hex (base-16) representation of the number is: ",0
    msg5        db "A",0 ;These will be implemented when I get the 
    msg6        db "B",0 ;hexadecimal loop working to change 10, 11, 
    msg7        db "C",0 ;etc. to their hex equivalents.
    msg8        db "D",0
    msg9        db "E",0
    msg10       db "F",0

    .UDATA
    num1            resw 1
    quotient        resw 1
    remainder       resw 1

    .CODE
    .STARTUP
    PutStr msg1
    nwln
    GetInt [num1]

    nwln
    PutStr msg2
    nwln
    mov AX, [num1]      
    sub BH, BH

    binary_loop:
    push AX 
    mov BH, byte 2 
    div BH ;All loops output the remainders in reverse order at the moment.
    mov [remainder], AH ;I was thinking of maybe moving the remainder value
    PutInt [remainder] ;to a stack then calling it at the end of the loop,
    mov [quotient], AL ;when the quotient value is zero. However,  
    mov AX, [quotient] ;I do not know enough to make that work. Any help
    cmp [quotient], byte 0 ;would be greatly appreciated
    jz binary_done ;Could also be je, as both do the same thing
    loop binary_loop

    binary_done:
    nwln
    PutStr msg3
    nwln
    mov AX, [num1]
    sub BH, BH      

    octal_loop:     
    push AX
    mov BH, byte 8
    div BH
    mov [remainder], AH
    PutInt [remainder]
    mov [quotient], AL
    mov AX, [quotient]
    cmp [quotient], byte 0
    jz octal_done
    loop octal_loop

    octal_done:
    nwln
    PutStr msg4
    nwln
    mov AX, [num1]      
    sub BH, BH  

    hex_loop:
    push AX
    mov BH, byte 16
    div BH
    mov [remainder], AH
    PutInt [remainder]
    mov [quotient], AL
    mov AX, [quotient]
    cmp [quotient], byte 0
    jz done
    loop hex_loop

    done:
    .EXIT

对于一个16位的测试数字155,当前的输出结果为: 二进制:11011001 八进制:332 十六进制:119

1个回答

2

你的代码存在三个主要问题:

  • 它以相反的顺序显示数字
  • 它将十六进制数字显示为整数(例如0xB会显示为11)
  • 注释非常不好(汇编语言不是高级语言)

你的代码还存在其他问题:

  • 没有有效利用寄存器(将数据存储在较慢的变量中)
  • 代码重复 - 一个接受“基数”输入的单一例程会减少代码大小一半
  • 滥用宏(“语言中的语言”);这使得难以理解代码(例如我无法确定PutInt是函数调用还是内联代码,也无法知道它使用/破坏哪些寄存器),并且使正确优化其周围的指令变得不可能

对于第一个问题,最好的方法是在内存中以相反的顺序构建字符串,然后打印结果字符串。对于第二个问题,你需要停止使用PutInt - 每个数字应该转换为一个字符。

例如(32位80x86,NASM,未经测试):

;Convert unsigned integer to string
;
;Input
; eax = integer
; ebx = base
;
;Output
; edi = address of string
;
;Trashed
; eax,edx

    section .bss
tempString: resb 33              ;Worst case string size is 32 digits
                                 ; (for base2), plus string terminator
tempStringEnd:
    section .text

convertIntegerToString:
    mov byte [tempStringEnd-1],0 ;Store string terminator
    mov edi,tempStringEnd-2      ;edi = address to store last character

.nextDigit:
    xor edx,edx                  ;edx:eax = current value
    div ebx                      ;eax = new current value, edx = next digit
    add dl,'0'                   ;dl = character for next digit maybe
    cmp dl,'9'                   ;Is the character correct?
    jbe .gotChar                 ; yes
    add dl,'A'-'0'-10            ; no, fix it up
.gotChar:
    mov [edi],dl                 ;Store the character
    dec edi                      ;edi = address for next character
    test eax,eax                 ;Is the current value zero?
    jne .nextDigit               ; no, do the next digit

    ret                          ;Done, EDI = address of completed string

谢谢您提供的解决方案,我会将其实现到我的语言中,并在有问题时与您联系。我刚开始接触汇编语言,之前主要使用Python、Java和C++等高级语言,因此在编码时仍然具有高级语言的倾向。 - Keeper of the Light

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接