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

TASM x86汇编用户输入合法性校验问题求助

TASM x86输入校验问题修复

问题分析与修复点

1. 输入数字仍返回无效的原因

DOS中断int 21h的0Ah号功能(读取字符串)要求缓冲区遵循固定结构:

  • 第1字节:缓冲区最大容纳字符数
  • 第2字节:实际输入的字符数(由系统填充)
  • 第3字节及以后:存储输入的字符(不含回车符)

你的代码中input_buffer仅定义了单个字节db 100,完全不符合0Ah的要求,导致输入数据存储混乱,校验逻辑读取到错误的起始位置,自然判定输入无效。

修复:
修改缓冲区定义为:

input_buffer db 100, 0, 100 dup(0)

同时,调用校验函数时,需要指向输入内容的起始位置(缓冲区+2),而非缓冲区开头:

; 原代码
mov si, offset input_buffer
; 修改为
mov si, offset input_buffer + 2

2. 第二次输入控制台冻结的原因

  • 第一次输入后未处理回车符,控制台光标停留在输入行末尾,第二次输入时输出提示和读取操作的交互异常;
  • 校验函数CheckNumberExit中的jmp valid_input跳过了ret指令,导致函数未正确返回,破坏了程序栈结构,后续执行逻辑混乱;
  • 输入缓冲区未重置,残留的旧数据可能干扰第二次输入校验。

修复:

  • 移除CheckNumberExit中的jmp valid_input,仅保留ret让函数正常返回:
CheckNumberExit:
    mov al, 1 ; 输入有效时置al=1
    ret ; 移除jmp valid_input
  • 在读取输入后添加换行处理,让光标回到新行:
; 读取输入后添加以下代码
mov ah, 02h
mov dl, 0Dh
int 21h
mov dl, 0Ah
int 21h
  • 在InvalidInput输出错误信息后,同样添加换行,并重置缓冲区的实际输入长度为0:
InvalidInput:
    mov ah, 09h
    mov dx, offset invalid_msg
    int 21h
    ; 添加换行
    mov ah, 02h
    mov dl, 0Dh
    int 21h
    mov dl, 0Ah
    int 21h
    ; 重置缓冲区实际长度
    mov byte ptr [input_buffer+1], 0
    xor al, al ; 置al=0表示无效
    ret

完整修复代码

.model small
.stack 200h
.data
        prompt_msg1 db "Enter the first number: $"
        prompt_msg2 db "Enter the second number: $"
        valid_input_msg db "valid input$"
        invalid_msg db "Invalid input, please enter a valid number $"
        ; 修复缓冲区结构:最大长度、实际长度、存储区
        input_buffer db 100, 0, 100 dup(0)
       
.code

start:
    mov ax, @data
    mov ds, ax

GetFirstNumber:
    ; 提示输入第一个数字
    mov ah, 09h
    mov dx, offset prompt_msg1
    int 21h

    ; 读取用户输入到缓冲区
    mov ah, 0Ah
    mov dx, offset input_buffer
    int 21h

    ; 处理回车换行,光标移至新行
    mov ah, 02h
    mov dl, 0Dh
    int 21h
    mov dl, 0Ah
    int 21h

    ; 校验输入有效性,指向输入内容起始位置
    mov si, offset input_buffer + 2
    call CheckNumber
    cmp al, 0
    je GetFirstNumber

GetSecondNumber:
    ; 提示输入第二个数字
    mov ah, 09h
    mov dx, offset prompt_msg2
    int 21h

    ; 读取用户输入到缓冲区
    mov ah, 02h
    mov dl, 0Dh
    int 21h
    mov dl, 0Ah
    int 21h
    mov ah, 0Ah
    mov dx, offset input_buffer
    int 21h

    ; 处理回车换行
    mov ah, 02h
    mov dl, 0Dh
    int 21h
    mov dl, 0Ah
    int 21h

    ; 校验输入有效性
    mov si, offset input_buffer + 2
    call CheckNumber
    cmp al, 0
    je GetSecondNumber

valid_input:
    ; 输出有效提示
    mov ah, 09h
    mov dx, offset valid_input_msg
    int 21h
    jmp Exit

CheckNumber:
    xor al, al
    mov bl, [si]
    ; 处理空输入
    cmp bl, 0Dh
    je InvalidInput
    cmp bl, '-'
    je CheckNumberSign
    cmp bl, '0'
    jl InvalidInput
    cmp bl, '9'
    jg InvalidInput
    inc si
    jmp CheckNumberDecimal

CheckNumberSign:
    inc si
    mov bl, [si]
    cmp bl, '0'
    jl InvalidInput
    cmp bl, '9'
    jg InvalidInput
    inc si
    jmp CheckNumberDecimal

CheckNumberDecimal:
    mov bl, [si]
    ; 输入结束符是回车(0Dh),不是0
    cmp bl, 0Dh
    je CheckNumberExit
    cmp bl, '.'
    je CheckNumberDecimalPoint
    cmp bl, '0'
    jl InvalidInput
    cmp bl, '9'
    jg InvalidInput
    inc si
    jmp CheckNumberDecimal

CheckNumberDecimalPoint:
    inc si
    mov bl, [si]
    cmp bl, '0'
    jl InvalidInput
    cmp bl, '9'
    jg InvalidInput
    inc si
    jmp CheckNumberDecimal

CheckNumberExit:
    mov al, 1 ; 输入有效时置al=1
    ret

InvalidInput:
    mov ah, 09h
    mov dx, offset invalid_msg
    int 21h
    ; 换行处理
    mov ah, 02h
    mov dl, 0Dh
    int 21h
    mov dl, 0Ah
    int 21h
    ; 重置缓冲区实际长度
    mov byte ptr [input_buffer+1], 0
    xor al, al ; 置al=0表示无效
    ret

Exit:
    mov ax, 4c00h
    int 21h

end start

额外说明:原代码中valid_input_msg和invalid_msg末尾的0是多余的,DOS 09h功能以$作为结束符,所以去掉了多余的0;校验逻辑中把结束符从0改为0Dh(回车),因为0Ah读取的输入内容末尾是回车,而非0。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 10:15:34