求大神指点实验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-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 jackz007 发表于 2019-2-15 23:35
做除法的时候,由于 dx 不为 0 导致溢出,只要略加修改便可解决问题:
还是会溢出。
为什么dx不为0会导致溢出呢? 本帖最后由 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]