peppapig 发表于 2019-2-15 21:50:55

求大神指点实验7

我只尝试了表格的四行输入,计算人均输入的时候计算了三个,计算第四个的时候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:
       mov es:,al
       mov al, ds:
       mov es:,al
       mov al, ds:
       mov es:,al
       mov al, ds:
       mov es:,al
       mov al,20h
       mov es:,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:
       mov es:, ax
       mov dx, ds:
       mov es:, 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:
       mov es:, 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:
       mov dx, ds:
       div word ptr ds:       
       mov es:, ax
       add si, 4
       add bp,2
       loop s3

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

运行结果

jackz007 发表于 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:
       mov es: , al
       mov al , ds:
       mov es: , al
       mov al , ds:
       mov es: , al
       mov al , ds:
       mov es: , al
       mov al , 20h
       mov es: , 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:
       mov es: , ax
       mov dx , ds:
       mov es: , 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:
       mov es: , 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:
       mov dx , ds:
       div word ptr ds:; 16 位除法,ax 保存商,dx 保存余数,如果不能整除,即埋下后续 div 运算溢出隐患      
       mov es: , ax
       add si , 4
       add bp , 2
       loop s3
       mov ax , 4c00h
       int 21h
codesg ends
end start

peppapig 发表于 2019-2-16 09:56:17

jackz007 发表于 2019-2-15 23:35
做除法的时候,由于 dx 不为 0 导致溢出,只要略加修改便可解决问题:

还是会溢出。
为什么dx不为0会导致溢出呢?

jackz007 发表于 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 寄存器清零

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

      所以,我修改的代码不可能还有溢出错误,楼主一定要认真查一查。
页: [1]
查看完整版本: 求大神指点实验7