在NASM中使用scanf将非整数输入无符号整数会导致循环问题

时间:2018-09-18 21:55:00

标签: nasm

每当我在循环中先前输入可接受的数字之后尝试在我的scanf中输入字母或符号以查找无符号整数时,它都会连续输入先前的数字,从而导致程序无限期地运行。我该如何解决?这是我编写的示例代码:

[bits 32]

global _main

extern _scanf
extern _printf

section .data
    prompt_number db "Please select a number. Enter 0 to escape. ", 0
    display_number db "You entered %u. ", 0
    number_fmt db "%u", 0
    number_input dd 0

section .bss

section .text
_main:
    push ebp
    mov ebp, esp
    and esp, 0xfffffff0

_Label:

    sub   esp, 16
    mov   dword[esp], prompt_number
    call  _printf
    add   esp, 16

    sub esp, 16
    mov dword[esp], number_fmt
    mov dword[esp+4], number_input
    call _scanf
    add esp, 16

    sub esp, 16
    mov dword[esp], display_number
    mov eax, [number_input]
    mov dword[esp+4], eax
    call _printf
    add esp, 16

    cmp dword[number_input], 0
    jne _Label

    mov   esp, ebp
    mov   eax, 1
    pop   ebp
ret 

1 个答案:

答案 0 :(得分:0)

这与scanf在这种情况下的工作方式有关,一种解决方案是从C移植针对Good way to flush scanf buffer when invalid entry entered的建议解决方案之一。

我的理解是,如果scanf无法将输入映射到格式字符串(在这种情况下,尝试将任意字符转换为无符号整数),则它放弃但不会从中删除任何内容输入缓冲区。因此,在这种情况下,随后对scanf的调用仅使用缓冲区中当前的内容。

以下是尝试移植第一个解决方案的快速尝试(使用getchar消耗缓冲区)。我不能保证它的质量。基本上这是我第一次进行程序设计组装:

[bits 32]

global _main

extern _getchar
extern _scanf
extern _printf

section .data
    prompt_number   db "Please select a number. Enter 0 to escape. ", 0
    display_number  db "You entered %u. ", 0
    scan_error      db "Error scanning input. ", 0
    number_fmt      db "%u", 0
    number_input    dd 0

section .bss

section .text
_main:
    push  ebp
    mov   ebp, esp
    and   esp, 0xfffffff0

_Label:

    sub   esp, 16
    mov   dword[esp], prompt_number
    call  _printf
    add   esp, 16

    sub   esp, 16
    mov   dword[esp], number_fmt
    mov   dword[esp+4], number_input
    call  _scanf
    add   esp, 16

    cmp   eax, 0
    jne    _ScanSuccess

_ScanError:
    sub   esp, 16
    mov   dword[esp], scan_error
    call  _printf
    add   esp, 16

_ScanErrorConsumeInput:
    sub   esp, 16
    call  _getchar
    add   esp, 16

    cmp   eax, -1   ; most common value indicating end-of-file
    je    _Label

    cmp   eax, 10   ; newline in ASCII
    je    _Label

    jmp   _ScanErrorConsumeInput

_ScanSuccess:
    sub   esp, 16
    mov   dword[esp], display_number
    mov   eax, [number_input]
    mov   dword[esp+4], eax
    call  _printf
    add   esp, 16

    cmp   dword[number_input], 0
    jne   _Label

_Return:
    mov   esp, ebp
    mov   eax, 1
    pop   ebp
    ret