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