8086汇编双字减法及结果十进制输出技术问询
嘿,我来帮你捋清楚8086汇编里双字减法、有符号数处理的问题,还有你提到的乘积存储逻辑~
首先,关于字相乘存双字的正确性
你说的完全没问题:8086里处理有符号字相乘必须用imul指令,它会自动把32位的乘积结果存在DX:AX(DX是高16位,AX是低16位)。你把第一个乘积存入双字变量minmax1(记得要定义成dd类型,比如minmax1 dd ?)是合理的;第二个乘积直接存在DX:AX里完全可行,后续减法时直接用寄存器操作反而更高效,不用额外写回内存。
双字有符号减法的正确姿势
8086确实不支持两个内存单元直接相减(比如sub [mem1], [mem2]是非法指令),所以必须借助寄存器中转。针对你的场景(minmax1(双字) - 第二个乘积(DX:AX)),正确的步骤应该是这样:
; 先把第二个乘积暂存到BX/CX,避免被覆盖 mov bx, ax mov cx, dx ; 把minmax1加载到DX:AX作为被减数 mov ax, word ptr minmax1 ; 取minmax1的低16位 mov dx, word ptr minmax1+2 ; 取minmax1的高16位 ; 执行双字减法:低16位先减,高16位带借位减 sub ax, bx ; 低16位相减,借位标记存在CF中 sbb dx, cx ; 高16位带借位相减,最终结果存在DX:AX
这里一定要用sbb(带借位减法)处理高16位,否则会丢失低16位相减产生的借位,导致双字结果错误。另外,因为是有符号数,全程用sub/sbb就对了,它们会自动处理符号位。
有符号双字转十进制输出的关键注意点
输出前必须先判断结果的符号:
- 检查
DX的最高位(也就是双字的第31位,符号位):用test dx, 8000h,如果结果不为0,说明是负数。 - 负数的话,先输出一个
'-',然后对DX:AX取反(neg ax,再sbb dx, 0——因为neg ax会产生借位,高16位要带借位减0才能正确取反),得到绝对值后再按无符号双字转十进制。 - 双字转十进制的通用逻辑是:循环把
DX:AX除以10,余数压入栈,直到商为0,再依次弹出栈里的余数转成ASCII输出(余数+30h就是对应数字的ASCII码)。
额外提醒
- 一定要用
imul而不是mul!mul是无符号乘法,处理负数相乘会得到错误的结果,只有imul才会正确计算有符号字的乘积。 - 双字变量
minmax1的存储顺序是小端模式:低16位存在minmax1,高16位存在minmax1+2,你存的时候要注意对应上,比如mov word ptr minmax1, ax(存低16位),mov word ptr minmax1+2, dx(存高16位),这部分你应该已经做对了。
举个完整的小片段参考(包含乘积、减法、输出的核心逻辑):
stack segment stack dw 100h dup(?) stack ends data segment min_niz1 dw -123 ; 示例有符号字变量 max_niz1 dw 456 ; 示例有符号字变量 minmax1 dd ? ; 存储第一个乘积的双字 mul2_a dw 78 ; 第二个乘法的第一个因子 mul2_b dw -9 ; 第二个乘法的第二个因子 data ends code segment start: mov ax, data mov ds, ax ; 计算第一个乘积:min_niz1 * max_niz1 mov ax, min_niz1 imul max_niz1 mov word ptr minmax1, ax mov word ptr minmax1+2, dx ; 计算第二个乘积:mul2_a * mul2_b mov ax, mul2_a imul mul2_b ; 结果存在DX:AX ; 执行双字减法:minmax1 - (DX:AX) mov bx, ax mov cx, dx mov ax, word ptr minmax1 mov dx, word ptr minmax1+2 sub ax, bx sbb dx, cx ; 处理输出 test dx, 8000h jz print_pos ; 输出负号 mov ah, 02h mov dl, '-' int 21h ; 取反得到绝对值 neg ax sbb dx, 0 print_pos: ; 调用双字转十进制输出函数(这里简化实现) call print_dword_dec ; 程序退出 mov ah, 4ch int 21h ; 函数:打印DX:AX中的无符号双字十进制数 print_dword_dec proc push bx push cx push dx mov cx, 0 mov bx, 10 next_div: div bx ; AX = (DX*65536 + AX)/10,DX = 余数 push dx ; 余数压栈 mov dx, 0 ; 重置DX为0,准备下一次除法 inc cx ; 计数加1 or ax, ax ; 判断商是否为0 jnz next_div ; 弹出栈输出 print_loop: pop dx add dl, 30h ; 转ASCII mov ah, 02h int 21h loop print_loop pop dx pop cx pop bx ret print_dword_dec endp code ends end start
内容的提问来源于stack exchange,提问作者nick_name
相关产品推荐
相关产品推荐

