NASM用户输入转整数异常:输入与变量对比出现随机值问题
问题根源与修复方案
核心问题:输入的ASCII字符串未转成数值
你直接把用户输入的ASCII字符串加载到寄存器里和num比较,这是错误的。比如输入"64",内存里存的是0x36('6'的ASCII码)、0x34('4'的ASCII码)、0x0a(换行符)这些字节,mov eax, [guess]会把连续4个字节拼成一个32位整数(比如0x0a343600),这自然和num的64(0x40)不相等,所以调试时看到的是“随机值”。
你提到的那段“能工作”的代码,其实只是在比较两个ASCII字符串的二进制值,不是真正的数值比较——比如输入"100"和"99",因为'1'的ASCII码(0x31)比'9'(0x39)小,代码会错误判断100比99小,只是你测试的是位数相同的数字,结果碰巧一致而已。
具体错误与修复步骤
添加ASCII转整数的逻辑
必须把用户输入的字符串转换成二进制整数,才能和num做数值比较。可以写一个简单的转换函数:遍历输入的每个字符,减去'0'的ASCII码(0x30),逐步累加计算数值。修复win段的打印错误
print num, 2是错误的,num是equ定义的常量,不是内存地址。需要把num的值转成ASCII字符串存入内存,再调用打印宏。初始化并更新猜测次数
guesses变量从未初始化,打印的是垃圾值。需要在程序开始时把它设为0,每次猜测后加1。处理输入的换行符
系统调用read会把用户输入的换行符也读入缓冲区,转换数值时要跳过这个字符,同时还要过滤非数字输入。
修正后的代码示例
section .data enter_msg DB "Enter Your Guess : ", 0 enter_msg_len equ $-enter_msg invalid_input_msg DB "Invalid Input !!!", 0x0a, 0 invalid_input_msg_len equ $-invalid_input_msg input_out_of_range DB "Input Out Of Range !!!", 0x0a, 0 input_out_of_range_len equ $-input_out_of_range too_high_msg DB "Your Guess Is Too High !!!", 0x0a, 0 too_high_msg_len equ $-too_high_msg too_low_msg DB "Your Guess Is Too Low !!!", 0x0a, 0 too_low_msg_len equ $-too_low_msg win_msg_1 DB "You Won ! The Number Was ", 0 win_msg_1_len equ $-win_msg_1 win_msg_2 DB " And You Guessed It In ", 0 win_msg_2_len equ $-win_msg_2 win_msg_3 DB " Guesses !", 0x0a, 0 win_msg_3_len equ $-win_msg_3 num equ 64 num_str DB "64", 0x0a ; 预存num的ASCII字符串用于打印 num_str_len equ $-num_str section .bss guess resb 32 guesses resb 4 ; 用4字节存储整数足够 converted_num resb 4 temp_str resb 4 ; 临时存储猜测次数的ASCII字符串 section .text global _start _start: %macro print 2 mov eax, 4 mov ebx, 1 mov ecx, %1 mov edx, %2 int 0x80 %endmacro %macro input 2 mov eax, 3 mov ebx, 2 mov ecx, %1 mov edx, %2 int 0x80 %endmacro %macro exit 0 mov eax, 1 mov ebx, 0 int 0x80 %endmacro ; 初始化猜测次数为0 mov dword [guesses], 0 main_loop: print enter_msg, enter_msg_len input guess, 32 ; 猜测次数加1 inc dword [guesses] ; 调用字符串转整数函数 push guess call str_to_int mov [converted_num], eax ; 检查输入是否有效 cmp eax, -1 je invalid_input ; 检查输入范围(限定0-100) cmp eax, 0 jl out_of_range cmp eax, 100 jg out_of_range ; 比较转换后的数值和num mov ebx, num mov eax, [converted_num] cmp eax, ebx jl lower jg higher jz win invalid_input: print invalid_input_msg, invalid_input_msg_len jmp main_loop out_of_range: print input_out_of_range, input_out_of_range_len jmp main_loop lower: print too_low_msg, too_low_msg_len jmp main_loop higher: print too_high_msg, too_high_msg_len jmp main_loop win: print win_msg_1, win_msg_1_len print num_str, num_str_len print win_msg_2, win_msg_2_len ; 把猜测次数转成ASCII字符串 push dword [guesses] push temp_str call int_to_str print temp_str, eax print win_msg_3, win_msg_3_len jmp end end: exit ; 字符串转整数函数:输入栈上的字符串地址,返回eax=转换后的数值,失败返回-1 str_to_int: push ebp mov ebp, esp mov esi, [ebp+8] xor eax, eax xor ecx, ecx convert_loop: mov cl, [esi] ; 跳过换行符 cmp cl, 0x0a je convert_done ; 检查是否是数字字符 cmp cl, '0' jl convert_fail cmp cl, '9' jg convert_fail ; 计算数值:eax = eax*10 + (cl-0x30) imul eax, 10 sub cl, 0x30 add eax, ecx inc esi jmp convert_loop convert_done: pop ebp ret 4 ; 清理栈上的参数 convert_fail: mov eax, -1 pop ebp ret 4 ; 整数转字符串函数:输入栈上的缓冲区地址、整数,返回eax=字符串长度 int_to_str: push ebp mov ebp, esp mov eax, [ebp+12] mov edi, [ebp+8] xor ecx, ecx ; 处理0的特殊情况 cmp eax, 0 je handle_zero int_loop: xor edx, edx mov ebx, 10 div ebx add dl, 0x30 push dx inc ecx cmp eax, 0 jne int_loop ; 把栈中的字符存入缓冲区 mov esi, ecx store_loop: pop dx mov [edi], dl inc edi dec ecx jnz store_loop ; 字符串结尾加换行符(可选) mov byte [edi], 0x0a inc esi mov eax, esi pop ebp ret 8 handle_zero: mov byte [edi], '0' mov byte [edi+1], 0x0a mov eax, 2 pop ebp ret 8
补充说明
- 转换函数处理了非数字输入的情况,返回-1触发错误提示
- 增加了输入范围检查(0-100),符合猜数字游戏的常规逻辑
- 新增了整数转字符串函数,支持多位数的猜测次数打印
内容的提问来源于stack exchange,提问作者GoodErnest64
相关产品推荐
相关产品推荐

