【问题标题】:ASCII to decimal and vice versa for more than one character in NASMASCII 到十进制,反之亦然,用于 NASM 中的多个字符
【发布时间】:2014-10-20 15:56:59
【问题描述】:

我正在编写这个小程序,你输入一个被除数和一个除数,程序将输出商和余数。代码如下:

segment .data

prompt db "Please enter a number: ", 10
promptLen equ $-prompt
prompt2 db "Please enter the divisor: ", 10
prompt2Len equ $-prompt2
prompt3 db "Your quotient is: ",10
prompt3Len equ $-prompt3
prompt4 db "Your remainder is: ",10
prompt4Len equ $-prompt4

segment .bss

inputNum resb 2
inputDiv resb 2
quotient resb 2
remainder resb 2

segment .text

global _start

_start:

mov eax, 4
mov ebx, 1
mov ecx, prompt
mov edx, promptLen
int 80h

mov eax, 3
mov ebx, 0
mov ecx, inputNum
mov edx, 2
int 80h

mov eax, 4
mov ebx, 1
mov ecx, prompt2
mov edx, prompt2Len
int 80h

mov eax, 3
mov ebx, 0
mov ecx, inputDiv
mov edx, 2
int 80h

xor edx, edx
mov ax, [inputNum]
mov bx, [inputDiv]
and ax, 0xff
and bx, 0xff
sub ax, '0'
sub bx, '0'

div bx

add ax, '0'
add dx, '0'
mov [quotient], ax
mov [remainder], dx

mov eax, 4
mov ebx, 1
mov ecx, prompt3
mov edx, prompt3Len
int 80h

mov eax, 4
mov ebx, 1
mov ecx, quotient
mov edx, 2
int 80h

mov eax, 4
mov ebx, 1
mov ecx, prompt4
mov edx, prompt4Len
int 80h

mov eax, 4
mov ebx, 1
mov ecx, remainder
mov edx, 2
int 80h
jmp exit

exit:

mov eax, 1
xor ebx, ebx
int 80h

现在的代码方式,我只能处理一个字符的数字;通过减去“0”并将其重新添加到输出中。 谁能帮我用一种更有效的方式进行这种转换,这样我就不会被限制在只有一个字符的数字上?

【问题讨论】:

  • 你关心效率还是正确性?
  • 如果您不能使用 libc,您将不得不编写自己的转换例程。身边的例子很多。您可以 multiply each digit by 10 in a loop 进行文本转二进制,并在循环中除以 10 进行二进制转文本。
  • 如果您对代码的每一行进行注释,将会有很大帮助。
  • @User.1: 或者其中任何一个:)
  • @ScottHunter,我确实关心效率和正确性!

标签: assembly ascii nasm data-conversion


【解决方案1】:

不检查输入和错误:

segment .data

    prompt db "Please enter a number: "
    promptLen equ $-prompt
    prompt2 db "Please enter the divisor: "
    prompt2Len equ $-prompt2
    prompt3 db 10, "Your quotient is: "
    prompt3Len equ $-prompt3
    prompt4 db 10, "Your remainder is: "
    prompt4Len equ $-prompt4
    linefeed db 10

segment .bss

    inputNum resb 80
    inputDiv resb 80
    uNum resd 1
    uDiv resd 1
    uQuo resd 1
    uRem resd 1
    quotient resb 80
    quotientLen resd 1
    remainder resb 80
    remainderLen resd 1

segment .text
global _start

dec2eax:                            ; Arg ESI: ASCII-string (0x0A-terminated) with decimal digits
    xor eax,eax                     ; Result
    xor edx, edx                    ; Especially to clear the 32-bit-part of EDX

    .loop:
    mov dl, byte [esi]              ; Read digit
    cmp dl, 10                      ; End of string (SYS_READ - in certain cases not existent)?
    je .finish                      ; Yes: done
    lea eax, [eax*4+eax]            ; EAX = 5 * EAX ...
    add eax, eax                    ;   ... and EAX = 2 * EAX results in EAX = EAX * 10
    add esi, 1                      ; Increment pointer to string
    and dl, 0x0F                    ; Eliminate ASCII part of digit
    add eax, edx                    ; Add digit to result
    jmp .loop                       ; Next character

    .finish:
    ret                             ; Result: Converted unsigned integer in EAX

eax2dec:                            ; Arg EDI: Pointer to string that gets ASCII-characters
    mov ebx, 10                     ; Divisor
    xor ecx, ecx                    ; CX=0 (number of digits)

    .first_loop:
    xor edx, edx                    ; Attention: DIV applies also DX!
    div ebx                         ; DX:AX / BX = AX remainder: DX
    push dx                         ; LIFO
    inc cl                          ; Increment number of digits
    test eax, eax                   ; AX = 0?
    jnz .first_loop                 ; No: once more

    mov ebx, ecx                    ; Save strlen

    .second_loop:
    pop ax                          ; Get back pushed digit
    or al, 00110000b                ; AL to ASCII
    mov byte [edi], al              ; Save AL
    inc edi                         ; DI points to next character in string DECIMAL
    loop .second_loop               ; Until there are no digits left

    mov byte [edi], 0               ; End-of-string delimiter (ASCIZ)
    mov eax, ebx                    ; Return strlen in EAX
    ret

_start:

    mov eax, 4
    mov ebx, 1
    mov ecx, prompt
    mov edx, promptLen
    int 80h

    mov eax, 3
    mov ebx, 0
    mov ecx, inputNum
    mov edx, 80
    int 80h

    mov eax, 4
    mov ebx, 1
    mov ecx, prompt2
    mov edx, prompt2Len
    int 80h

    mov eax, 3
    mov ebx, 0
    mov ecx, inputDiv
    mov edx, 80
    int 80h

    mov esi, inputNum
    call dec2eax
    mov [uNum], eax

    mov esi, inputDiv
    call dec2eax
    mov [uDiv], eax

    xor edx, edx
    mov eax, [uNum]
    mov ebx, [uDiv]
    div ebx
    mov [uQuo], eax
    mov [uRem], edx

    mov eax, [uQuo]
    mov edi, quotient
    call eax2dec
    mov [quotientLen], eax
    mov eax, [uRem]
    mov edi, remainder
    call eax2dec
    mov [remainderLen], eax

    mov eax, 4
    mov ebx, 1
    mov ecx, prompt3
    mov edx, prompt3Len
    int 80h

    mov eax, 4
    mov ebx, 1
    mov ecx, quotient
    mov edx, [quotientLen]
    int 80h

    mov eax, 4
    mov ebx, 1
    mov ecx, prompt4
    mov edx, prompt4Len
    int 80h

    mov eax, 4
    mov ebx, 1
    mov ecx, remainder
    mov edx, [remainderLen]
    int 80h

    mov eax, 4
    mov ebx, 1
    mov ecx, linefeed
    mov edx, 1
    int 80h

    jmp exit

    exit:

    mov eax, 1
    xor ebx, ebx
    int 80h

【讨论】:

  • 非常感谢您的回答,但我想知道 dec2eax 和 eax2dec 背后的逻辑是什么。我是程序集的新手,我正在尝试了解如何在较低级别操作数据。如果您能详细说明,我将不胜感激。
  • @O.A.:这有点棘手。我的英语太糟糕了,无法简单清楚地解释它。看看 Jester 对您的问题的评论。你也可以用谷歌搜索它(“程序集转换号”),你会发现一堆例子和一些解释尝试。如果您(或您的翻译程序)懂德语,欢迎您访问我的主页:dcla.rkhb.de/umwandlung.html
猜你喜欢
  • 2015-09-13
  • 2011-07-29
  • 2011-02-02
  • 2014-09-20
  • 2018-09-22
  • 2011-03-23
  • 1970-01-01
  • 2014-10-27
  • 2011-11-15
相关资源
最近更新 更多