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

NASM中CMP指令始终返回jg的问题及求和程序实现需求

NASM汇编代码问题点评与解决方案

核心问题分析

  • 字符串转数值逻辑缺失:你尝试用sub转换输入,但没处理负号,也没逐位累加计算真实数值。输入的是ASCII字符串(比如"-3"是字符'-'和'3'),直接用sub处理只能得到单个字符的ASCII差值,不是真正的数值。
  • 比较对象错误:如果寄存器里存的是ASCII字符而非二进制数值,cmp比较的是ASCII码值。比如'-'的ASCII是45,比0大,自然会触发jg跳转,根本没在比较数字本身。
  • 循环逻辑不闭环:缺少完整的输入读取、数值转换、累加和终止判断的流程,导致功能无法正常运行。

解决方案

关键步骤

  1. 实现字符串转数值函数:
    • 先识别负号标记,再逐字符将ASCII转成数字,通过累乘10+当前数字计算绝对值
    • 负数结果通过补码规则(取反加1)转换
  2. 修正比较逻辑:转成二进制数值后再用cmp判断正负或零
  3. 构建完整循环:读取输入→转数值→判断是否为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 21:50:38