You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

x86-32汇编:字符串转整数后输出异常的解决方法

问题描述

需要编写x86-32位汇编程序,实现以下功能:读取包含3个整数的输入字符串(如“30 40 2”),将其转换为整数并存入独立寄存器,最后按number 1: (num1), number 2: (num2), number 3: (num3).格式输出。

现有代码在输入“100 999 1”时,输出结果为“100 999 99 1”,存在异常。原代码如下:

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 
问题分析
  1. 输入处理不规范:sys_read读取的输入包含换行符,且未添加null终止符,可能导致字符串转换时读取到缓冲区垃圾数据;同时读取长度设置过小(10字节),无法容纳较长输入。
  2. 字符串转换逻辑错误:IntegerToString函数反转步骤中多余的dec edi导致反转范围错误,包含缓冲区中未初始化的垃圾数据或之前转换的残留内容。
  3. 输出逻辑错误:固定输出整个缓冲区大小(12字节),会将缓冲区中未使用的无效内容一并输出,导致显示异常。
  4. 空格跳过逻辑缺陷:NextInt只能跳过单个空格,无法处理连续空格的情况,且逻辑冗余。
修复方案

以下是修复后的完整代码:

section .data
    prompt1 db 'number 1: '
    prompt1_len equ $ - prompt1
    prompt2 db ', number 2: '
    prompt2_len equ $ - prompt2
    prompt3 db ', number 3: '
    prompt3_len equ $ - prompt3
    prompt_end db '.'
    prompt_end_len equ $ - prompt_end
    numStrSize equ 12

section .bss
    input resb 30    ; 预留30字节输入缓冲区
    num1 resd 1
    num2 resd 1
    opCode resd 1
    str_buffer resb numStrSize

section .text
    global _start

_start:
    ; 读取用户输入,最多29字节(留1字节存null)
    mov eax, 3
    mov ebx, 0
    mov ecx, input
    mov edx, 29
    int 80h
    ; 将换行符替换为null终止符
    mov byte [input + eax], 0

    ; 转换第一个整数
    mov esi, input
    call convertToInt
    mov [num1], eax

    ; 跳转到第二个整数
    call NextInt
    call convertToInt
    mov [num2], eax

    ; 跳转到第三个整数
    call NextInt
    call convertToInt
    mov [opCode], eax

    ; 按指定格式输出
    ; 输出number 1: 
    mov eax, 4
    mov ebx, 1
    mov ecx, prompt1
    mov edx, prompt1_len
    int 80h
    ; 输出num1
    mov eax, [num1]
    mov ecx, str_buffer
    call IntegerToString
    mov eax, 4
    mov ebx, 1
    mov ecx, str_buffer
    int 80h

    ; 输出, number 2: 
    mov eax, 4
    mov ebx, 1
    mov ecx, prompt2
    mov edx, prompt2_len
    int 80h
    ; 输出num2
    mov eax, [num2]
    mov ecx, str_buffer
    call IntegerToString
    mov eax, 4
    mov ebx, 1
    mov ecx, str_buffer
    int 80h

    ; 输出, number 3: 
    mov eax, 4
    mov ebx, 1
    mov ecx, prompt3
    mov edx, prompt3_len
    int 80h
    ; 输出opCode
    mov eax, [opCode]
    mov ecx, str_buffer
    call IntegerToString
    mov eax, 4
    mov ebx, 1
    mov ecx, str_buffer
    int 80h

    ; 输出结尾的点
    mov eax, 4
    mov ebx, 1
    mov ecx, prompt_end
    mov edx, prompt_end_len
    int 80h

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

; 字符串转整数:ESI指向输入字符串,返回值在EAX
convertToInt:
    xor eax, eax
    .Loop:
        movzx ebx, byte [esi]
        test ebx, ebx
        jz .end
        cmp ebx, ' '
        je .end
        sub ebx, '0'
        imul eax, eax, 10
        add eax, ebx
        inc esi
        jmp .Loop
    .end:
        ret

; 整数转字符串:EAX为整数,ECX指向输出缓冲区,返回时EDX为字符串长度
IntegerToString:
    ; 清空缓冲区
    mov edi, ecx
    mov ecx, numStrSize
    xor eax, eax
    rep stosb
    mov ecx, edi ; 恢复ECX为缓冲区地址

    mov ebx, 10
    mov edi, ecx + numStrSize - 2 ; 从倒数第二个字节开始存(最后一个留作null)
    mov byte [ecx + numStrSize - 1], 0 ; 末尾设为null

    .convert_loop:
        xor edx, edx
        div ebx
        add dl, '0'
        mov [edi], dl
        dec edi
        test eax, eax
        jnz .convert_loop

    ; 将数字移到缓冲区开头
    mov esi, edi + 1
    mov edi, ecx
    .copy_loop:
        mov al, [esi]
        mov [edi], al
        test al, al
        jz .copy_done
        inc esi
        inc edi
        jmp .copy_loop
    .copy_done:
        ; 计算字符串长度
        mov edx, edi
        sub edx, ecx
        ret

; 跳过所有连续空格,ESI指向第一个非空格字符或null
NextInt:
    .skip_spaces:
        movzx ebx, byte [esi]
        test ebx, ebx
        jz .end
        cmp ebx, ' '
        jne .end
        inc esi
        jmp .skip_spaces
    .end:
        ret 

关键修复点说明

  1. 输入处理:
    • 调整sys_read的读取长度为29,预留1字节存储null终止符;
    • 读取后手动添加null终止符,替换输入中的换行符,确保字符串转换时能正确识别结束位置。
  2. 整数转字符串:
    • 每次转换前清空缓冲区,避免残留旧数据;
    • 移除反转步骤中多余的dec edi,改为将数字从缓冲区末尾复制到开头,简化逻辑并避免范围错误;
    • 返回实际字符串长度,输出时仅输出有效内容,避免无效字符。
  3. 空格跳过逻辑:
    • 简化NextInt函数,改为循环跳过所有连续空格,兼容多空格分隔的输入。
  4. 格式输出:
    • 添加格式字符串,严格按照要求的格式输出内容。

内容的提问来源于stack exchange,提问作者Matt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 17:30:55