鱼C论坛

 找回密码
 立即注册
查看: 3007|回复: 3

求大神指点实验7

[复制链接]
发表于 2019-2-15 21:50:55 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
我只尝试了表格的四行输入,计算人均输入的时候计算了三个,计算第四个的时候dosbox死机了。求指点。
看起来不像除法溢出,因为1356/13=104=68H,不会超过一个寄存器AX,AX可以放两个字节。也没有除数为0的情况。
assume cs:codesg, ds:datasg, ss:stacksg
datasg segment
  db '1975','1976','1977','1978'
  dd 16,22,382,1356
  dw 3,7,9,13
datasg ends
stacksg segment
  dw 0,0,0,0,0,0,0,0
stacksg ends
table segment
  db 4 dup('year summ ne ?? ')
table ends
codesg segment
start: mov ax,datasg
       mov ds,ax
       mov ax,stacksg
       mov ss,ax
       mov sp,16
       mov ax,table
       mov es,ax
      
       ;读入年份,bx表示哪一列的偏址,si表示数据段的偏址,di表示目标表格里行造成的偏址

       mov bx,0
       mov si,0
       mov cx,4
    s0:mov ax,si
       mov di,4
       mul di
       mov di,ax
       mov al, ds:[bx+si+0]
       mov es:[bx+di+0],al
       mov al, ds:[bx+si+1]
       mov es:[bx+di+1],al
       mov al, ds:[bx+si+2]
       mov es:[bx+di+2],al
       mov al, ds:[bx+si+3]
       mov es:[bx+di+3],al
       mov al,20h
       mov es:[bx+di+4],al
       add si,4
       loop s0
      
       ;读入收入
       add bx,5
       mov si,0
       mov cx,4


    s1:mov ax,si
       mov di,4
       div di
       mov di,10H
       mul di
       mov di,ax
       mov ax, ds:[si+16]
       mov es:[bx+di+0], ax
       mov dx, ds:[si+18]
       mov es:[bx+di+2], dx
       add si, 4
       loop s1
   
       ;读入雇员数
       add bx,5
       mov si,0
       mov cx,4

    s2:mov ax,si
       mov di, 2
       div di
       mov di,10H
       mul di
       mov di,ax
       mov ax, ds:[si+32]
       mov es:[bx+di+0], ax
       add si, 2
       loop s2
      
       ;计算人均收入=收入/雇员数
       add bx,3
       mov si,0
       mov bp,0       
       mov cx,4

    s3:mov ax,si
       mov di, 4
       div di
       mov di,10H
       mul di
       mov di,ax
       mov ax, ds:[si+16]
       mov dx, ds:[si+18]
       div word ptr ds:[bp+32]       
       mov es:[bx+di+0], ax
       add si, 4
       add bp,2
       loop s3

       mov ax,4c00h
       int 21h
codesg ends
end start

运行结果
QQ截图20190215213239.jpg
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-2-15 23:35:09 | 显示全部楼层
本帖最后由 jackz007 于 2019-2-16 11:44 编辑

      做除法的时候,由于 dx 不为 0 导致溢出,只要略加修改便可解决问题:

   
assume cs:codesg, ds:datasg, ss:stacksg
datasg segment
    db '1975' , '1976' , '1977' , '1978'
    dd     16 ,     22 ,    382 ,   1356
    dw      3 ,      7 ,      9 ,     13
datasg ends
stacksg segment
    dw 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
stacksg ends
table segment
    db 4 dup('year summ ne ?? ')
table ends
codesg segment
start: mov ax , datasg
       mov ds , ax
       mov ax , stacksg
       mov ss , ax
       mov sp , 16
       mov ax , table
       mov es , ax
       ; 读入年份,bx 表示哪一列的偏址,si表示数据段的偏址,di表示目标表格里行造成的偏址
       mov bx , 0
       mov si , 0
       mov cx , 4
    s0:mov ax , si
       mov di , 4
       mul di
       mov di , ax
       mov al , ds:[bx+si+0]
       mov es:[bx+di+0] , al
       mov al , ds:[bx+si+1]
       mov es:[bx+di+1] , al
       mov al , ds:[bx+si+2]
       mov es:[bx+di+2] , al
       mov al , ds:[bx+si+3]
       mov es:[bx+di+3] , al
       mov al , 20h
       mov es:[bx+di+4] , al
       add si , 4
       loop s0
       ; 读入收入
       add bx , 5
       mov si , 0
       mov cx , 4
    s1:mov ax , si
       cwd                      ; 新增此句,防止做除法时 dx 不为零
       mov di , 4
       div di
       mov di , 10H
       mul di
       mov di , ax
       mov ax , ds:[si+16]
       mov es:[bx+di+0] , ax
       mov dx , ds:[si+18]
       mov es:[bx+di+2] , dx
       add si , 4
       loop s1
       ; 读入雇员数
       add bx , 5
       mov si , 0
       mov cx , 4
    s2:mov ax , si
       cwd                      ; 新增此句,防止做除法时 dx 不为零
       mov di , 2
       div di
       mov di , 10H
       mul di
       mov di , ax
       mov ax , ds:[si+32]
       mov es:[bx+di+0] , ax
       add si , 2
       loop s2
       ; 计算人均收入 = 收入 / 雇员数
       add bx , 3
       mov si , 0
       mov bp , 0        
       mov cx , 4
    s3:mov ax , si
       cwd                      ; 新增此句,防止做除法时 dx 不为零
       mov di , 4
       div di                   ; 除法溢出发生点,原因,做除法时 dx 不为零
       mov di , 10H
       mul di
       mov di , ax
       mov ax , ds:[si+16]
       mov dx , ds:[si+18]
       div word ptr ds:[bp+32]  ; 16 位除法,ax 保存商,dx 保存余数,如果不能整除,即埋下后续 div 运算溢出隐患       
       mov es:[bx+di+0] , ax
       add si , 4
       add bp , 2
       loop s3
       mov ax , 4c00h
       int 21h
codesg ends
end start
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-2-16 09:56:17 | 显示全部楼层
jackz007 发表于 2019-2-15 23:35
做除法的时候,由于 dx 不为 0 导致溢出,只要略加修改便可解决问题:

还是会溢出。
为什么dx不为0会导致溢出呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-2-16 10:59:09 | 显示全部楼层
本帖最后由 jackz007 于 2019-2-17 00:47 编辑
peppapig 发表于 2019-2-16 09:56
还是会溢出。
为什么dx不为0会导致溢出呢?


        因为 16 位除法中,被除数是  dx : ax,运算结果 ax 保存商,dx 保存余数,如果运算结果商的值太大,超出 16 位,ax 无法保存,势必会产生溢出。被除数是 32 位,而除数只有 16 位,这种情况很容易产生。

        为了证明这一点,可以在 debug 中输入以下代码然后进行调试得到验证:
mov dx , 2
xor ax , ax
push dx
pop cx
div cx
int3 

        以上代码实际上是计算

        20000h / 2h

        计算结果,商 = 10000h,由于 ax 无法存储此值,所以导致溢出错误,所谓 dx 不为 0 导致溢出,说的正是这种情况 。

        楼主在代码中一共有 4 处使用了 16 位除法,除了最后那 1 处,前面的 3 处都没有专门为 dx 寄存器赋过值。也未对 dx 寄存器进行任何的处理,这是很严重的问题,因为不论你是否意识到, 寄存器 dx 注定是要参与运算的!

        所以,在做 16 位除法运算时,如果没有专门用到 dx 寄存器,必须事先用下面的指令之一来处理 dx 寄存器:
cwd          ;  把寄存器 ax 的值扩展到 dx 成为 32 位数
或
xor dx , dx  ;  把 dx 寄存器清零

        只有这样做,才能保证计算结果的正确。

        所以,我修改的代码不可能还有溢出错误,楼主一定要认真查一查。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-24 09:38

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表