1

我想创建一个可以计算除法问题的程序。问题是当我尝试用负数分割时,我的程序崩溃了,尽管我创建了一个名为“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 
+4

只是第一次看;你有:'je DivZero; je DivNeg'一个又一个;还有DivNeg应该怎么做?为什么有一个' - 'ascii? –

+0

我创建了DivNeg循环,以便显示除负数的结果和余数。没有它,程序会因某种原因崩溃。作为divNeg的一部分,如果除数小于零,我会将它放在那里。 – Jaquai

+2

我想你应该多读一些关于asm的内容; '循环'没有意义 - 它eax> 0它将永远循环。整个问题对于它应该完成的任务有点“奇怪” –

回答

1

cdq/idiv ebx将仅2例提高#DE(除法异常):

  • 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没有办法因正分红和负分割而发生故障。您正确使用cdqeax标记为edx:eax。 (如果没有这一点,64b/32b => 32b划分很容易溢出结果。)

如果你没有崩溃在idiv本身,那么你有一个不同的bug,并应该单步执行代码在调试器中。请参阅标记wiki的底部,了解有关使用GDB进行调试或使用Visual Studio进行调试的提示。

+0

我更新了一下:在'je DivZero'下,我添加了'cmp ebx,0',然后'jnae DivNeg'。在 'DivNeg:' 循环,更新为 'MOV EBX,0', \t 'CMP \t \t EBX,-1' \t 'JGE \t \t Done2' \t 'MOV \t \t EAX,-1' \t 'neg \t \t eax' \t'je \t \t Done2'。当我调试程序时,它显示了正确的结果/余数,但它再次崩溃,指向'Done1'循环中的'mov [ebx],edx'。 – Jaquai

+0

@Jaquai:看看'ebx'中的值并找出它为什么不是一个有效的指针。从程序中的前一个步骤中单步执行代码,然后观察寄存器值发生变化,以查看您是如何到达那里的。 –

+0

在'Done1'循环中,'[ebx]'应该是结果,'edx'是余数。即使在调试程序后,我仍然无法弄清楚它为什么崩溃。其他一切运行良好(除负数之外)。另外,在'DivNeg'循环中没有东西跳到'Done1'。 – Jaquai

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 

非常有问题的代码这一个! (无限循环vs不想要的循环)。
最好写:

Done1: 
    mov [ebx], edx ;Return remainder 
    jmp Done2 

如果我是你,我把我的DONE1标签,三线高了,因此检查,以防范空指针总是完成。

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