NASM中CMP指令始终返回jg的问题及求和程序实现需求
NASM汇编代码问题点评与解决方案
核心问题分析
- 字符串转数值逻辑缺失:你尝试用
sub转换输入,但没处理负号,也没逐位累加计算真实数值。输入的是ASCII字符串(比如"-3"是字符'-'和'3'),直接用sub处理只能得到单个字符的ASCII差值,不是真正的数值。 - 比较对象错误:如果寄存器里存的是ASCII字符而非二进制数值,
cmp比较的是ASCII码值。比如'-'的ASCII是45,比0大,自然会触发jg跳转,根本没在比较数字本身。 - 循环逻辑不闭环:缺少完整的输入读取、数值转换、累加和终止判断的流程,导致功能无法正常运行。
解决方案
关键步骤
- 实现字符串转数值函数:
- 先识别负号标记,再逐字符将ASCII转成数字,通过
累乘10+当前数字计算绝对值 - 负数结果通过补码规则(取反加1)转换
- 先识别负号标记,再逐字符将ASCII转成数字,通过
- 修正比较逻辑:转成二进制数值后再用
cmp判断正负或零 - 构建完整循环:读取输入→转数值→判断是否为0→累加→循环,直到输入0时退出并输出总和
完整可运行代码
section .data prompt db 'Enter a number (0 to exit): ', 0x0a prompt_len equ $ - prompt output db 'Sum is: ', 0x0a output_len equ $ - output newline db 0x0a section .bss input_buf resb 20 ; 存储输入字符串,预留足够空间 sum resd 1 ; 总和存储,初始化为0 section .text global _start _start: mov dword [sum], 0 ; 初始化总和为0 read_loop: ; 打印输入提示 mov eax, 4 mov ebx, 1 mov ecx, prompt mov edx, prompt_len int 0x80 ; 读取用户输入(Linux系统调用) mov eax, 3 mov ebx, 0 mov ecx, input_buf mov edx, 20 int 0x80 ; 调用字符串转数值函数 push input_buf call str_to_num add esp, 4 ; 判断输入是否为0,是则退出循环 cmp eax, 0 je print_sum ; 非0则累加到总和 add dword [sum], eax jmp read_loop print_sum: ; 打印结果提示 mov eax, 4 mov ebx, 1 mov ecx, output mov edx, output_len int 0x80 ; 将总和转成字符串以便打印 push dword [sum] push input_buf ; 复用input_buf存储转换后的字符串 call num_to_str add esp, 8 ; 打印总和字符串 mov eax, 4 mov ebx, 1 mov ecx, input_buf mov edx, eax ; num_to_str返回字符串长度在eax中 int 0x80 ; 打印换行 mov eax, 4 mov ebx, 1 mov ecx, newline mov edx, 1 int 0x80 ; 退出程序 mov eax, 1 xor ebx, ebx int 0x80 ; 字符串转数值函数: ; 输入:栈顶参数为字符串地址 ; 返回:eax = 转换后的二进制数值 str_to_num: push ebp mov ebp, esp push ebx push ecx push edx push esi mov esi, [ebp+8] ; 取字符串地址 xor eax, eax ; 初始化结果寄存器 xor ebx, ebx ; 负数标记(0=正,1=负) xor ecx, ecx ; 当前字符存储 ; 检查首字符是否为负号 mov cl, byte [esi] cmp cl, '-' jne process_digits inc ebx ; 标记为负数 inc esi ; 跳过负号字符 process_digits: mov cl, byte [esi] ; 判断是否到输入结束(换行符或空字符) cmp cl, 0x0a je str_to_num_done cmp cl, 0 je str_to_num_done ; ASCII字符转数字:减去'0'的ASCII值 sub cl, '0' ; 计算结果 = 结果*10 + 当前数字 mov edx, 10 mul edx add eax, ecx inc esi jmp process_digits str_to_num_done: ; 如果是负数,对结果取反(补码转换) cmp ebx, 1 jne str_to_num_exit neg eax str_to_num_exit: pop esi pop edx pop ecx pop ebx mov esp, ebp pop ebp ret ; 数值转字符串函数: ; 输入:栈顶参数依次为数值、存储字符串的地址 ; 返回:eax = 转换后的字符串长度 num_to_str: push ebp mov ebp, esp push ebx push ecx push edx push esi push edi mov eax, [ebp+8] ; 取要转换的数值 mov edi, [ebp+12] ; 取字符串存储地址 mov esi, edi ; 保存起始地址用于计算长度 xor ebx, ebx ; 负数标记 ; 处理负数 cmp eax, 0 jge num_to_str_process neg eax ; 取绝对值 mov byte [edi], '-' inc edi inc ebx num_to_str_process: xor ecx, ecx ; 计数位数 mov edx, 10 num_to_str_div: xor edx, edx div edx ; eax=商,edx=余数 push edx ; 保存余数(数字的逆序) inc ecx cmp eax, 0 jne num_to_str_div num_to_str_build: pop edx add dl, '0' ; 余数转ASCII字符 mov byte [edi], dl inc edi dec ecx jnz num_to_str_build mov byte [edi], 0 ; 添加字符串结束符 ; 计算字符串长度 sub edi, esi mov eax, edi pop edi pop esi pop edx pop ecx pop ebx mov esp, ebp pop ebp ret
代码说明
str_to_num:负责把输入的ASCII字符串转换成二进制数值,支持正负整数,解决了你之前转换失败的问题num_to_str:把二进制数值转回ASCII字符串,因为系统调用只能打印字符串- 循环逻辑:每次读取输入后转成数值,判断是否为0,非0则累加到总和,直到输入0时输出结果
- 所有比较操作都是针对真实的二进制数值,不会再出现ASCII码比较的错误
内容的提问来源于stack exchange,提问作者hail1401
相关产品推荐
相关产品推荐

