每当我尝试在先前在循环中输入已接受的数字后,在我的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
这与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