如何在 x86-32 汇编中将整数转换为字符串?

问题描述 投票:0回答:2

我想用x86-32位汇编编写一个程序,输入由3个整数组成的字符串,即30 40 2。然后将其转换为整数,将其放置到单独的寄存器中。最后,以字符串形式输出,格式为“数字 1:(num1),数字 2:(num2),数字 3:(num3)。”

这是我的代码:

section .data
    num db '0'  ; Initialize for number with value 0 of ASCII
    res db 0    ; decalre a byte res with value 0
    numStrSize equ 12

section .bss
   input resb 30    ; Reserves a buffer input of 10 bytes for user input.
    num1 resd 1
    num2 resd 1
    opCode resd 1
    str_buffer resb numStrSize

section .text
    global _start

_start:
    ; Read input from user
    mov eax, 3     ; Sets up a sys_read system call (system call number 3).
    mov ebx, 0     ; Specifies file descriptor 0 (standard input).
    mov ecx, input ; Points ecx to the input buffer.
    mov edx, 10    ; Increase to match buffer size
    int 80h        ; Executes the system call (reads user input into input buffer).

   ; Convert string to integer
    mov esi, input      ; ESI points to the start of input
    call convertToInt
    mov [num1], eax

    call NextInt
    call convertToInt
    mov [num2], eax

    call NextInt
    call convertToInt
    mov [opCode], eax

    mov eax, [num1]
    mov ecx, str_buffer
    call IntegerToString
    mov eax, 4
    mov ebx, 1
    mov ecx, str_buffer
    mov edx, numStrSize
    int 80h

    mov eax, [num2]
    mov ecx, str_buffer
    call IntegerToString
    mov eax, 4
    mov ebx, 1
    mov ecx, str_buffer
    mov edx, numStrSize
    int 80h

    mov eax, [opCode]
    mov ecx, str_buffer
    call IntegerToString
    mov eax, 4
    mov ebx, 1
    mov ecx, str_buffer
    mov edx, numStrSize
    int 80h

exit:
    mov eax, 1
    xor ebx, ebx
    int 80h

convertToInt:
    xor eax, eax        ; Clear EAX for storing result
    .Loop:
        movzx ebx, byte [esi]  ; Move one byte of input into EBX
        test ebx, ebx          ; Test if byte is null terminator (end of string)
        jz .end
        cmp ebx, ' '             ; Check if the character is a whitespace
        je .end      ; If whitespace, jump to skip_character
        sub ebx, '0'           ; Convert ASCII to integer (subtract ASCII value of '0')
        imul eax, eax, 10      ; Multiply current result by 10 (shift left by one decimal place)
        add eax, ebx           ; Add new digit to result
        inc esi
        jmp .Loop
    .end:
        ret

IntegerToString:
    mov ebx, 10              ; Set divisor to 10
    mov edi, ecx             ; Set EDI to point to the start of the buffer
    mov byte [edi], 0        ; Null-terminate the string

    .convert:
        add edi, numStrSize - 1  ; Move EDI to the end of the buffer
    .convert_loop:
        dec edi              ; Move back one byte in the buffer
        xor edx, edx         ; Clear EDX for division
        div ebx              ; Divide EAX by 10, result in EAX, remainder in EDX
        add dl, '0'          ; Convert remainder to ASCII character
        mov [edi], dl        ; Store ASCII character in buffer
        test eax, eax        ; Check if EAX is zero
        jnz .convert_loop    ; If not zero, continue loop

    .reverse:
        mov esi, ecx
        dec edi                  ; Decrement EDI to exclude null terminator
        jmp .start_reverse
    .start_reverse:
        .reverse_loop:
            cmp esi, edi         ; Check if pointers have crossed
            jge .done            ; If so, the string is reversed
            mov al, [esi]        ; Swap the characters
            mov bl, [edi]
            mov [esi], bl
            mov [edi], al
            inc esi              ; Move to next characters
            dec edi
            jmp .reverse_loop
        .done:
            ret


NextInt:
    .loop:
        movzx ebx, byte [esi]
        test ebx, ebx
        jz .end
        cmp ebx, ' '
        je .skipSpace
        inc esi
        jmp .loop
    .skipSpace:
        inc esi
        jmp .end
    .end:
        ret 

我尝试打印我保存的 3 个整数。即我的输入是 100 999 1,但我得到的输出是:

100 999 99 1

我该如何解决这个问题?

assembly x86
2个回答
1
投票

为什么IntegerToString中有反转代码?
转换已按正确的顺序存储十进制字符

这就是 12 字节 str_buffer 的样子:

?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
mov edi, ecx      ; Set EDI to point to the start of the buffer
mov byte [edi], 0 ; Null-terminate the string
0, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
^
EDI
  add edi, numStrSize - 1  ; Move EDI to the end of the buffer
0, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
                                 ^
                                 EDI
.convert_loop:
  dec edi              ; Move back one byte in the buffer
  add dl, '0'          ; Convert remainder to ASCII character
  mov [edi], dl        ; Store ASCII character in buffer
0, ?, ?, ?, ?, ?, ?, ?, ?, ?, '0', ?
                               ^
                               EDI
.convert_loop:
  dec edi              ; Move back one byte in the buffer
  add dl, '0'          ; Convert remainder to ASCII character
  mov [edi], dl        ; Store ASCII character in buffer
0, ?, ?, ?, ?, ?, ?, ?, ?, '0', '0', ?
                            ^
                            EDI
.convert_loop:
  dec edi              ; Move back one byte in the buffer
  add dl, '0'          ; Convert remainder to ASCII character
  mov [edi], dl        ; Store ASCII character in buffer
0, ?, ?, ?, ?, ?, ?, ?, '1', '0', '0', ?
                         ^
                         EDI

您可以做的唯一后处理是将缓冲区中的字符向下移动,以便您每次打印的地址保持不变。但最好将字符保留在原处,然后将 ECX 设置为 EDI 中的地址并使用 EDX 保存实际长度(在 num1 = 100 的情况下为 3)返回。


0
投票

所以我终于得到了我想要的输出。感谢那些帮助我的人。这是更正后的代码。

.text
   global _start

_start:
    ; Read input from user
    mov eax, 3     ; Sets up a sys_read system call (system call number 3).
    mov ebx, 0     ; Specifies file descriptor 0 (standard input).
    mov ecx, input ; Points ecx to the input buffer.
    mov edx, 30    ; Increase to match buffer size
    int 80h        ; Executes the system call (reads user input into input buffer).
    ; Convert string to integer
    mov esi, input      ; ESI points to the start of input
    call convertToInt
    mov [num1], eax

    call NextInt
    call convertToInt
    mov [num2], eax

    call NextInt
    call convertToInt
    mov [opCode], eax

    mov eax, [num1]
    mov esi, str_buffer
    call IntegerToString
    mov ecx,eax
    mov eax, 4
    mov ebx, 1
    mov edx, numStrSize
    int 80h

    mov eax, [num2]
    mov esi, str_buffer
    call IntegerToString
    mov ecx,eax
    mov eax, 4
    mov ebx, 1
    mov edx, numStrSize
    int 80h

    mov eax, [opCode]
    mov esi, str_buffer
    call IntegerToString
    mov ecx,eax
    mov eax, 4
    mov ebx, 1
    mov edx, numStrSize
    int 80h

exit:
    mov eax, 1
    xor ebx, ebx
    int 80h

convertToInt:
    xor eax, eax        ; Clear EAX for storing result
    .Loop:
        movzx ebx, byte [esi]  ; Move one byte of input into EBX
        test ebx, ebx          ; Test if byte is null terminator (end of string)
        jz .end
        cmp ebx, ' '             ; Check if the character is a whitespace
        je .end      ; If whitespace, jump to skip_character
        sub ebx, '0'           ; Convert ASCII to integer (subtract ASCII value of '0')
        imul eax, eax, 10      ; Multiply current result by 10 (shift left by one decimal place)
        add eax, ebx           ; Add new digit to result
        inc esi
        jmp .Loop
    .end:
        ret

IntegerToString:
    add esi, 9
    mov byte [esi], 0  ; String terminator
    mov ebx, 10
    .next_digit:
        xor edx, edx        ; Clear edx prior to dividing edx:eax by ebx
        div ebx             ; eax /= 10
        add dl, '0'         ; Convert the remainder to ASCII 
        dec esi            ; store characters in reverse order
        mov [esi], dl
        test eax, eax            
        jnz .next_digit    ; Repeat until eax==0
        ; return a pointer to the first digit (not necessarily the start of the provided buffer)
        mov eax, esi
        ret

NextInt:
    .loop:
        movzx ebx, byte [esi]
        test ebx, ebx
        jz .end
        cmp ebx, ' '
        je .skipSpace
        inc esi
        jmp .end
    .skipSpace:
        inc esi
        jmp .end
    .end:
        ret 

section .bss
    input resb 30
    numStrSize equ 10
    num1 resd 1
    num2 resd 1
    opCode resd 1
    str_buffer resb numStrSize
© www.soinside.com 2019 - 2024. All rights reserved.