【问题标题】:Assembly: How to convert hex input to decimal?汇编:如何将十六进制输入转换为十进制?
【发布时间】:2014-03-19 04:56:28
【问题描述】:

我发现了很多关于这个问题的问题,但是,我无法让我的代码运行。我的程序应该取一个十六进制值,检查它是否是一个有效的十六进制字符,然后将十六进制值显示为十进制值。如果是小写十六进制字符,则需要将其转换为大写。所有这些都需要循环。

除了将十六进制转换为十进制之外,我已经完成了所有这些工作。我在程序中有我认为应该转换它的代码,但它不会编译。我将在代码下方列出编译器错误。如果标签 convert: 中的代码被注释掉(除了最后一行,“jmp display”),那么程序将正常运行,但显然不会将值显示为小数。

使用 nasme 编译:“nasm -fbin getChar.asm -o getChar.com -l getChar.lst”

我在 dosbox 中运行程序。

; This program gets a char from user and prints it out as a decimal 

    org 100h        ; program start point
section .data
    msgIn:  DB  13, 10, "Enter a Hex Digit: $"
    msgOut: DB  13, 10, "Decimal Value: $"
    msgOpt: DB  13, 10, "Enter another?(y or n): $"
    errMsg: DB  13, 10, "Illegal character, Enter 0..9 or A..F: $"
    HNUM:   DB  19H
    NUM:    DB  0
    D:      DB  10h
    H:      DB  16
    CNT:    DB  0

section .text

continue:               ; start of loop
        mov dx, msgIn   ; offset address of message to display
        mov ah, 9       ; print string function
        int 21h

        mov ah, 1       ; keyboard input sub-program
        int 21h         ; read character into al
        mov cl, al

legal:                  ; compare input to see if valid
        cmp cl, 48      ; cl < 0
        jl  end_if      ; yes, error msg
        cmp cl, 70      ; cl > F
        jg  check_case  ; yes, error msg

        jmp prntMsg2    ; print value of input

check_case:             ; check case of input
        cmp cl, 97      ; cl < a
        jl  end_if      ; yes, error msg
        cmp cl, 102     ; cl > f
        jg  end_if      ; yes, error msg

        jmp to_upper    ; need to send to function to convert to upper case
                        ; then pass to prntMsg2

to_upper:
        and al, 223 ; convert to upper case(0DFh)

        jmp prntMsg2

end_if:                 ; error message if invalid input
        mov ah, 9
        mov dx, errMsg  ; print error message
        int 21h

        jmp continue    ; get a new value

prntMsg2:               ; print second message*****
        mov dx, msgOut  ; offset of second message
        mov ah, 9       ; print string function
        int 21h         ; display message

convert:
        mov cx, 00
        mov dx, 00

    L6: mov ax, 00
        mov al, [HNUM]
        div word [D]
        mov [HNUM], al

        mov bx, ax
        mov cl, 0
        mov ax, 1
    L5: 
        cmp cl, 00
        je L7
        mul word [H]
        sub cl, 1
        jmp L5
    L7: 
        mul bh
        add dx, ax
        add word [CNT], 1
        cmp word [HNUM], 0
        jg L6
        mov [NUM], dl

        jmp display

display:                ; display character
        mov dl, al
        mov ah, 2       ; print char function
        int 21h

        mov ah, 9       ; see if user wants to do it again
        mov dx, msgOpt
        int 21h

        mov ah, 1
        int 21h
        mov bl, al
        cmp bl, 'y'     ; bl = y
        jne exitPrg     ; no, end

        jmp continue    ; get a new value

exitPrg:                ; exit program
        mov ah, 4ch     ; exit to DOS function
        int 21h         ; see you later!

上面的代码已经过编辑,现在可以编译和运行了。但是,它仍然没有正确地进行从十六进制到十进制的转换。它根本不显示值,只是空白。如果输入字母,即使是字母 a-f,它也会挂断。一个数字不挂,但还是不显示值。

现在我已经运行它,至少我可以修复它,但是,任何指导都值得赞赏。感谢 Gene 让我开始工作。

【问题讨论】:

    标签: assembly hex decimal x86-16


    【解决方案1】:

    NASM 内存操作数使用方括号来表示取消引用。所以例如你会想要:

        mov al, [HNUM]
        div byte [D]
        mov [HNUM], al
    

    NASM Manual 解释了这一点。实时调频!

    没有括号,标签被视为等于内存位置地址的立即操作数。第一行没有语法错误,但导致al 被加载HNUM 地址的低字节。不是你想要的。 div 是一个错误,因为 8086 没有除以立即数的指令。 mov 是无稽之谈,因为您不能写入立即值。

    所以错误消息告诉您出了什么问题。在引用的行中,操作数与其指令不符。

    加法

    我继续安装了 dosbox 和 NASM。实际上 NASM 在推断操作数类型方面不如 MASM 聪明。所以对于div 指令,您需要byte,(不是word),如上所示。我无法理解你的算法。它比必要的复杂。这是我的版本:

    ; This program gets a hex digit from user and prints it out as a decimal 
    
            org 100h        ; program start point
    
    section .data
    
    msgIn:  DB      13, 10, "Enter a hex digit or q to quit: $"
    msgErr: DB      " isn't hex. Must be 0-9, A-F, or a-f.$"
    msgOut: DB      " has decimal value $"
    buffer: DB      "xxxxx"
    endBuf: DB      ".$"
    ten:    DB      10
    
    section .text
    
    continue:               ; start user interaction
            mov dx, msgIn   ; offset address of message to display
            mov ah, 9       ; print string function
            int 21h
    
    get_hex_digit:
            mov ah, 1
            int 21h         ; read character into al
    
    check_for_quit:
            cmp al, 'q'     ; handle quit character
            je exit
            cmp al, 'Q'
            je exit
    
    check_for_digit:
            cmp al, '0'     ; handle 0-9
            jl check_for_upper
            cmp al, '9'
            jg check_for_upper
            sub al, '0'     ; convert to numeric value
            jmp print_decimal
    
    check_for_upper:
            cmp al, 'A'     ; handle A-F
            jl check_for_lower
            cmp al, 'F'
            jg check_for_lower
            sub al, 'A'-10  ; convert to numeric value
            jmp print_decimal
    
    check_for_lower:
            cmp al, 'a'     ; handle a-f
            jl handle_digit_error
            cmp al, 'f'
            jg handle_digit_error
            sub al, 'a'-10  ; convert to numeric value
    
    print_decimal:          ; print al contents as decimal 0-255
            mov di, endBuf  ; set buffer pointer to char after digits
    next_digit:
            dec di          ; advance buffer pointer to next char
            xor ah, ah      ; clear high byte of ax for division
            div byte [ten]  ; ah = ax % 10, al = ax / 10
            add ah, '0'     ; convert ah to ascii
            mov [di], ah    ; copy to buffer
            or al, al       ; set condition codes with al
            jnz next_digit  ; jump if more digits to print
    
    print_digits:
            mov dx, msgOut  ; offset address of message preamble
            mov ah, 9       ; print string function
            int 21h
            mov dx, di      ; offset address of converted digits
            mov ah, 9       ; print string function
            int 21h
    
            jmp continue    ; otherwise, get next input
    
    handle_digit_error:
            mov dx, msgErr  ; offset address of message to display
            mov ah, 9       ; print string function
            int 21h
            jmp continue
    
    exit:                   ; exit program
            mov ah, 4ch     ; exit to DOS function
            int 21h         ; see you later!
    

    【讨论】:

    • 修复了它,我还需要在使用它们之前添加“单词”。我用修复程序编辑了上面的代码。虽然我没有得到正确的结果,但它现在可以运行了。
    • 我怀疑你是否想要大小说明符word,因为变量是字节。
    • 一开始我没有单词说明符。除非我把它放在那里,否则它不会编译。我是不是搞错了?
    • @Beetle 如果你想要将 AX 除以一个字节的除法指令,你应该说byte 而不是word。我没有使用过 NASM,但在 MASM 中,如果您 not 在 DB 标签后使用冒号,则操作数的大小将从标签中推断出来。冒号擦除大小信息。 NASM 文档似乎也表明这在 NASM 中也有效。
    • NASM 从不从您声明标签的方式或从其后面的指令推断操作数大小。通常你会选择mov cx, 10 / div cxdiv cl 或其他任何方式,选择任何免费寄存器。 (通常你会通过使用 16 位操作数大小进行除法来处理 16 位整数,因此你必须将 DX 设为零)。但如果你真的只有 1 个十六进制数字作为输入,那么商肯定不会溢出一个字节。 (小数点后的 10 位是 0 或 1,因此您可以对此进行优化。)
    【解决方案2】:

    check_for_upper:

        cmp al, 'A'     ; handle A-F
        jl check_for_lower
    

    这应该是:

        jl handle_digit_error
    

    因为 Ucase "A" 是 41h,而 Lcase "a" 是 61h

    【讨论】:

      猜你喜欢
      • 2016-08-21
      • 2012-06-02
      • 2019-05-16
      • 1970-01-01
      • 2015-09-13
      • 2013-10-08
      • 2011-07-28
      • 1970-01-01
      相关资源
      最近更新 更多