.model small
.data
nizA db 1,2,3,4,5,6,7,8
nizB db 8 dup(?)
len equ 8
.code
main proc
mov si,0
mov di,0
mov cx,len
program:
mov al,nizA[si] ;problem is here it always stores CDh in AL
cbw ;convert AL to AX so i can divide
mov bl,2 ;The number I want to divide so I test if its even or not
div bl ;Overflow message
cmp ah,0
je next:
input:
mov dl,nizA[si]
mov nizB[di],dl
inc di
next:
add si,2
loop program
endp
end
我这里有这段代码,用于我需要制作的期末考试,非常简单。从给定数组的偶数索引中查找奇数。因此,这自然意味着我将 SI
增加 2,并将该数组元素放入 AL
中。但无论数组中的数字是什么,AL
中存储的始终是十六进制数字 CD,然后,如果它按预期存储,我想做 CBW
code> 转换为 AX
并能够与 BL
相除
我现在只收到来自 EMU 8086 的错误消息:
divide error - overflow. to manually process this error, change address of INT 0 in interrupt vector table.
这肯定与CD号有关,我这里只有两个问题
- 正在存储 CD 而不是 1
- 溢出(很可能是因为 CD 太高,但我仍然将数字相除,它们只会减少,所以有点没有意义)
最佳答案
“正在存储 CD,而不是 1”
当 DOS .EXE 启动时,DS
段寄存器不指向程序的 .data 部分! DS 段寄存器指向 ProgramSegmentPrefix 又名 PSP。这 256 字节的区域是 DOS 保存有关正在运行的程序的一些重要数据的地方,并且您可以在偏移地址 128 处检索程序的命令行。
当代码运行时,您发现了值 CDh,因为它恰好是 PSP 中的第一个字节。它是始终启动 PSP 的 int 20h
指令的操作码。
您需要编写以下内容:
.code
main proc
mov ax, @data
mov ds, ax
“溢出(很可能是因为 CD 太高,但我仍然将数字相除,它们只会减少,所以有点没有意义)”
其实也有道理。因为您使用 CBW
将被除数扩展到 AX
,并且 AL
中的值错误地为 CDh,所以 中的新值AX
变为 FFCDh。当您的代码将其除以 2(使用 mov bl, 2
div bl
)时,商远大于除法专用商寄存器中可以存储的值 AL
。这就是为什么你会得到“除法错误”。
解决方案
- 验证此次划分是否有效的解决方案:
mov ax, @data
mov ds, ax
mov si, 0
mov di, 0
mov cx, len/2
program:
mov al, nizA[si]
mov ah, 0 ; For UNSIGNED division don't use CBW
mov bl, 2
div bl
cmp ah, 0 ; Remainder
je next
mov dl, nizA[si] ; Reload
mov nizB[di], dl
inc di
next:
add si, 2
loop program
- 避免划分而支持
TEST
的解决方案,并添加一些额外的改进:
mov ax, @data
mov ds, ax
xor si, si ; Better than 'mov si, 0` for zeroing a register
xor di, di ; idem
program:
mov al, nizA[si]
test al, 1
jz IsEven
mov nizB[di], al ; Only storing 'odd' values
inc di
IsEven:
add si, 2 ; Next 'even' index
cmp si, len
jb program
了解 TEST AL, 1
如何在 AL
寄存器上实现非破坏性,因此您无需在写入之前重新加载该值nizB 数组?
另请注意,您并不总是需要单独的循环计数器。这里我使用了源数组索引。
关于assembly - EMU 8086 在寄存器中存储错误的数组元素值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69153092/