我想创建一个可以计算除法问题的程序。问题是,当我尝试除以负数时,我的程序崩溃了,即使我创建了一个名为" DivNeg"应该是为了防止它崩溃。有没有人有关于如何解决这个问题的想法?
这是我的汇编代码
.386
.model flat
public _Divide
.code
_Divide proc
mov eax, [esp + 4] ; First address ; this is the dividend
mov ebx, [esp + 8] ; Second address ; this is the divisor
cmp ebx, 0
je DivZero
cmp ebx, 0
jnae DivNeg
cdq
idiv ebx ; To divide by eax by ebx
mov ebx, [esp + 12] ; Third address; this is the remainder
jmp Done1
DivZero:
mov eax,-1 ; If user divides by zero, this will set the result to negative 1
mov edx, 0 ; If user divides by zero, this will set the remainder to 0
mov ebx,[esp +12] ; Needed for the remainder if divided by 0
cmp ebx, 0
je Done2
Done1:
mov [ebx], edx
je Done1
DivNeg:
cmp ebx, 0
jge Done2
mov eax, -1
neg eax
je DivNeg
Done2:
ret
_Divide endp
end
答案 0 :(得分:1)
cdq
/ idiv ebx
只会在两种情况下引发#DE(Divide Exception):
eax
=任何内容,ebx
= 0.除以零。eax
= 0x80000000,ebx
= -1。这会溢出,因为正确的答案不适合eax
。 2的补码有符号表示中的最负数(最高幅度)没有反转。 -2^31
符合带符号的32位整数,但+2^31
不适合。 (在C中,这就是为什么INT_MIN / -1
是未定义的行为。)有关详细信息,请参阅Why does integer division by -1 (negative one) result in FPE?。由于溢出是不可能的,cdq
/ idiv ebx
无法判断正分红和负除数。您正在使用cdq
将eax
签名扩展为edx:eax
。 (没有它,64b / 32b => 32b除法很容易溢出结果。)
如果您没有在idiv
本身崩溃,那么您有一个不同的错误,应该在调试器中单步执行代码。有关使用GDB或Visual Studio进行调试的提示,请参阅x86标记wiki的底部。
答案 1 :(得分:1)
mov eax, [esp + 4] ; First address ; this is the dividend mov ebx, [esp + 8] ; Second address ; this is the divisor ... mov ebx, [esp + 12] ; Third address; this is the remainder
这些评论表明您的功能的参数是地址。这意味着您需要取消引用才能对值本身进行任何操作。你为第三个参数正确地做了这个,但在第一个和第二个参数上失败了!
mov eax, [esp + 4] ; First address
mov eax, [eax] ; this is the dividend
mov ebx, [esp + 8] ; Second address
mov ebx, [ebx] ; this is the divisor
cmp ebx, 0 je DivZero cmp ebx, 0 jnae DivNeg
您不需要重复cmp
指令。标志保持为第二次条件跳转设置。另外,因为EQ条件被淘汰,最好使用jna
,或者更好地使用jl
。
cmp ebx, 0
je DivZero
jl DivNeg
Done1: mov [ebx], edx je Done1
这个代码非常有问题! (无限循环与不必要的掉落) 更好写:
Done1:
mov [ebx], edx ;Return remainder
jmp Done2
如果我是你,我会放置 Done1 标签,高出3行,以便始终完成防止空指针的检查。
Done1:
mov ebx,[esp +12] ; Needed for the remainder if divided by 0
cmp ebx, 0
je Done2
mov [ebx], edx
jmp Done2
如果红利和分配器均为正值,您可以安全地使用div
代替idiv
。
当被除数为正且除法器为负时你可以否定除法器,像以前一样使用div
,但否定商。
DivNeg:
neg ebx
cdq
div ebx
neg eax
jmp Done1