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

x86汇编长除法20位小数输出问题:栈读取仅显示零

解决x86汇编除法小数位输出全零的问题

我来帮你搞定这个问题——你遇到的输出全零的情况,核心是对16位x86栈的元素大小理解有误,再加上栈地址计算逻辑出错导致读取了栈中无效的空数据。咱们一步步拆解问题:

核心错误分析

  1. 栈元素大小误解:在16位x86汇编中,push ax压入的是16位(2字节)数据,不是你假设的8字节。20个这样的元素总共占用20*2=40字节,而不是你代码里的20*8=160字节。这直接导致你计算的栈地址完全偏离了实际存储数据的位置,读取的是栈中未被写入的零值区域。
  2. 栈地址方向搞反:16位栈是向下生长的(SP值随push操作递减),你第一次压入的小数位会存在栈的更深处(更高的内存地址),最后压入的在栈顶(更低的SP地址)。你原来的地址递增逻辑(add bx,8h)完全不符合栈的存储顺序。

修正方案

我们可以通过保存初始栈指针(用BP寄存器,因为BP默认指向栈基址,不会随push/pop改变),然后从第一个压入的元素地址开始,依次读取输出:

  1. 在开始压栈前保存初始栈顶地址到BP;
  2. 计算第一个压入元素的地址:初始栈顶地址减2(因为第一次push会让SP减2,第一个元素就存在初始SP-2的位置);
  3. 循环读取时,每次将地址减2(因为更早压入的元素在更高地址),直到读完20位。

修正后的完整代码

dane SEGMENT ;segment danych
text db 0dh, 0ah,"Give b (a/b)", 0dh, 0ah, "$"
text2 db 0dh, 0ah,"Give a (a/b)", 0dh, 0ah, "$"
text3 db 0dh, 0ah,"a/b:", 0dh, 0ah, "$"
quot db 0h
rem db 0h
counter db 0h
dane ENDS
; C:\ml /Fl /Zm /Zi /c lab3.asm
; E:\link /CODEVIEW lab3.obj
rozkazy SEGMENT 'CODE' use16 ;segment rozkazu
ASSUME cs:rozkazy, ds:dane
start:
 mov ax, SEG dane
 mov ds, ax
 mov cl, 03h
 mov ch, 0Ah
 mov dx, offset text
 mov ah, 09h
 int 21h ; "input divisor"
 mov ah, 01h
 int 21h ; input into al
 mov cl, al
 sub cl, 30h ; move to cl and subtract 30h to get value instead of ascii
 mov dx, offset text2
 mov ah, 09h
 int 21h ; "input dividend"
 mov ah, 01h
 int 21h
 sub al, 30h ; input into al and get number instead of ascii
 mov bp, sp ; 保存初始栈顶地址,此时还未压入任何小数位
 jmp divide
divide:
 cbw
 div cl ; convert al to ax and divide by cl
 mov dl, ah
 push ax ; push the quotient digit (ax contains 00xxh)
 mov al, dl ; move remainder from division to al
 xor ah, ah ; clear ah (替代多余的cbw,更直观)
 mul ch ; multiply remainder by 10 for next iteration
 inc counter ; increase counter by 1
 cmp counter, 14h ; check if we've calculated 20 digits
 jz show
 jmp divide
show:
 mov dx, offset text3
 mov ah, 09h
 int 21h ; "your number"
 mov bx, bp
 sub bx, 2 ; 定位到第一个压入的小数位地址
show2:
 mov al, [bx] ; 取出商的数字(低字节,因为ax是00xxh)
 add al, 30h ; 转ASCII
 mov dl, al
 mov ah, 02h
 int 21h ; 输出当前位
 sub bx, 2 ; 移动到下一个更早压入的元素地址
 dec counter
 cmp counter, 0h
 jz finish ; if counter = 0 jump to finish
 jmp show2
finish:
 mov ah, 4CH
 int 21H
rozkazy ENDS
stosik SEGMENT stack
 dw 128 dup(?)
stosik ENDS
END start

额外优化说明

  • 去掉了多余的cbw指令:在将余数放入al后,用xor ah, ah直接清空ah比cbw更直观(因为余数是0-9的正数,cbw也能得到正确结果,但xor更清晰);
  • 用BP保存初始栈地址:BP寄存器不会被push/pop操作修改,是定位栈中数据的可靠基准;
  • 直接读取栈元素的低字节al:因为我们push的ax是00xxh(xx是商的数字),直接取低字节更高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:11:17