x86汇编长除法20位小数输出问题:栈读取仅显示零
解决x86汇编除法小数位输出全零的问题
我来帮你搞定这个问题——你遇到的输出全零的情况,核心是对16位x86栈的元素大小理解有误,再加上栈地址计算逻辑出错导致读取了栈中无效的空数据。咱们一步步拆解问题:
核心错误分析
- 栈元素大小误解:在16位x86汇编中,
push ax压入的是16位(2字节)数据,不是你假设的8字节。20个这样的元素总共占用20*2=40字节,而不是你代码里的20*8=160字节。这直接导致你计算的栈地址完全偏离了实际存储数据的位置,读取的是栈中未被写入的零值区域。 - 栈地址方向搞反:16位栈是向下生长的(SP值随push操作递减),你第一次压入的小数位会存在栈的更深处(更高的内存地址),最后压入的在栈顶(更低的SP地址)。你原来的地址递增逻辑(
add bx,8h)完全不符合栈的存储顺序。
修正方案
我们可以通过保存初始栈指针(用BP寄存器,因为BP默认指向栈基址,不会随push/pop改变),然后从第一个压入的元素地址开始,依次读取输出:
- 在开始压栈前保存初始栈顶地址到BP;
- 计算第一个压入元素的地址:初始栈顶地址减2(因为第一次push会让SP减2,第一个元素就存在初始SP-2的位置);
- 循环读取时,每次将地址减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
相关产品推荐
相关产品推荐

