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

汇编阶乘程序输出头部出现异常字符问题求助

问题分析与修复

你的阶乘程序头部出现异常字符,核心问题出在ASCII转换阶段的寄存器滥用和错误内存写入,具体问题点如下:

关键错误点

  1. 寄存器ecx被重复误用
    你一开始把ecx作为转换循环的计数器并清零,但在循环内部又将其赋值为10(除数),之后还执行inc ecx——这完全破坏了计数器的功能,最后用ecx作为输出长度自然也是错误的。

  2. 错误的内存写入操作
    转换循环里的mov [fac],bl是致命错误:bl是当前指向fac缓冲区的指针(比如fac+11的低8位),你把这个地址值直接写入fac的第一个字节,这就把随机的非数字ASCII字符(比如地址的低8位对应的ASCII)放到了结果的开头,这就是你看到的-、,、+等异常字符的来源。

  3. 长度计算逻辑混乱
    由于ecx被滥用,最后传递给sys_write的edx(输出长度)完全不正确,导致输出内容包含多余字节。

修复后的代码

section .data
    msg db 'Enter a number: ',0     ; 用户提示内容
    lenmsg equ $ - msg              ; 提示长度
    disp db 'Factorial: ',0         ; 输出提示内容
    lendisp equ $ - disp            ; 输出提示长度
    newline db 0xa                  ; 换行符

section .bss
    num resb 3              ; 2字节存数字,1字节存换行
    fac resb 12             ; 12字节存阶乘结果

section .text
    global _start

_start:

    ; 显示用户提示
    mov edx,lenmsg              ; 写入字节数
    mov ecx,msg                 ; 写入内容
    mov ebx,1                   ; 文件描述符:stdout
    mov eax,4                   ; 系统调用:sys_write
    int 0x80                    ; 调用内核

    ; 读取用户输入
    mov edx,2                   ; 读取字节数
    mov ecx,num                 ; 输入存储位置
    mov ebx,0                   ; 文件描述符:stdin
    mov eax,3                   ; 系统调用:sys_read
    int 0x80                    ; 调用内核
    mov byte [num+eax-1],0      ; 替换换行符为null

    ; 计算阶乘
    movzx eax, byte [num]       ; 将num移入eax,高位补零
    sub eax,'0'                 ; ASCII转整数
    mov ecx,eax                 ; 移入ecx作为计数器
    mov eax,1                   ; eax初始化为1,存储阶乘结果
    cmp ecx,0                   ; 判断输入是否为0
    jz output                   ; 输入为0直接跳转到输出
loop_calc:
    mul ecx                     ; 阶乘乘法
    dec ecx                     ; 计数器减1
    jnz loop_calc               ; 计数器>0则循环

output:

    ; 整数转ASCII
    mov ebx,fac+11              ; 指向fac缓冲区末尾
    mov byte [ebx],0            ; 添加结束符
    xor edi,edi                 ; 用edi作为计数器,避免和ecx冲突
convert:
    xor edx,edx                 ; 清零edx(除法余数寄存器)
    mov ecx,10                  ; 除数为10
    div ecx                     ; eax = eax/10,edx=余数
    add dl,'0'                  ; 余数转ASCII
    dec ebx                     ; 缓冲区指针左移
    mov [ebx],dl                ; 存储当前数字
    inc edi                     ; 计数器加1
    test eax,eax                ; 判断eax是否为0
    jnz convert                 ; eax不为0则继续循环

    ; 显示输出提示
    mov edx,lendisp             ; 输出提示长度
    mov ecx,disp                ; 输出提示内容
    mov ebx,1                   ; 文件描述符:stdout
    mov eax,4                   ; 系统调用:sys_write
    int 0x80                    ; 调用内核

    ; 显示阶乘结果
    mov edx,edi                 ; 结果长度(计数器edi的值)
    mov ecx,ebx                 ; 结果起始地址(ebx指向第一个有效数字)
    mov ebx,1                   ; 文件描述符:stdout
    mov eax,4                   ; 系统调用:sys_write
    int 0x80                    ; 调用内核

    ; 显示换行
    mov edx,1                   ; 换行符长度
    mov ecx,newline             ; 换行符内容
    mov ebx,1                   ; 文件描述符:stdout
    mov eax,4                   ; 系统调用:sys_write
    int 0x80                    ; 调用内核

    ; 退出程序
    mov eax,1                   ; 系统调用:sys_exit
    int 0x80                    ; 调用内核

修复说明

  • 寄存器分离使用:用edi作为转换循环的计数器,避免和用作除数的ecx冲突,保证长度计算准确。
  • 移除错误写入:删掉mov [fac],bl这一行,不再向结果开头写入垃圾地址值。
  • 正确传递输出参数:输出阶乘时,用edi作为长度,ebx作为结果的起始地址(因为转换后ebx指向第一个有效数字),确保只输出有效数字部分。

测试修复后的代码,输入2-9的阶乘都会正常显示,比如输入9会输出Factorial: 362880,无异常字符。

内容的提问来源于stack exchange,提问作者nkminion

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 13:36:05