2016-04-15 7 views
0

Ich habe den folgenden Code, aber ich kann nicht herausfinden, warum, wenn die Nummer, die ich eingeben zu hoch ist, gibt es die falsche Nummer zurück. Es könnte wegen der Datentypen und Teilen und Multiplizieren sein, aber ich kann nicht genau herausfinden, warum. wenn Sie wissen, warum ich für die Hilfe dankbar wäre.Warum, wenn die Nummer, die ich eingeben, zu hoch wird, gibt es die falsche Nummer

.586 
.model flat, stdcall 
option casemap :none 
.stack 4096 
extrn [email protected]: proc 

GetStdHandle proto :dword 
ReadConsoleA proto :dword, :dword, :dword, :dword, :dword 
WriteConsoleA proto :dword, :dword, :dword, :dword, :dword 
STD_INPUT_HANDLE equ -10 
STD_OUTPUT_HANDLE equ -11 

.data 

    bufSize = 80 
    inputHandle DWORD ? 
    buffer db bufSize dup(?) 
    bytes_read DWORD ? 
    sum_string db "The number was ",0 
    outputHandle DWORD ? 
    bytes_written dd ? 
    actualNumber dw 0 
    asciiBuf db 4 dup (0) 
.code 
    main: 

    invoke GetStdHandle, STD_INPUT_HANDLE 
    mov inputHandle, eax 
    invoke ReadConsoleA, inputHandle, addr buffer, bufSize, addr bytes_read,0 
    sub bytes_read, 2 ; -2 to remove cr,lf 
    mov ebx,0 

    mov al, byte ptr buffer+[ebx] 
    sub al,30h 
    add [actualNumber],ax 
getNext: 
    inc bx 
    cmp ebx,bytes_read 
    jz cont 
    mov ax,10 
    mul [actualNumber] 
    mov actualNumber,ax 
    mov al, byte ptr buffer+[ebx] 
    sub al,30h 
    add actualNumber,ax 

    jmp getNext 
cont: 


    invoke GetStdHandle, STD_OUTPUT_HANDLE 
    mov outputHandle, eax 
    mov eax,LENGTHOF sum_string ;length of sum_string 
    invoke WriteConsoleA, outputHandle, addr sum_string, eax, addr bytes_written, 0 
    mov ax,[actualNumber] 
    mov cl,10 
    mov bl,3 
nextNum: 
    xor edx, edx 
    div cl 
    add ah,30h 
    mov byte ptr asciiBuf+[ebx],ah 
    dec ebx 
    mov ah,0 
    cmp al,0 
    ja nextNum 

    mov eax,4 

    invoke WriteConsoleA, outputHandle, addr asciiBuf, eax, addr bytes_written, 0 

    mov eax,0 
    mov eax,bytes_written 
    push 0 

    call [email protected] 
end  main 
+0

Microsoft hat einen netten Debugger in seiner Visual Studio-Umgebung. [Ollydbg] (http://www.ollydbg.de/) funktioniert auch gut. –

+0

Sie geben uns nicht wirklich viel, wenn Sie "zu hoch" und "falsche Zahl" sagen."Als Vermutung würde ich mir vorstellen, dass Sie versuchen, eine Nummer zu verwenden, die größer ist als die Größe, die Sie für Ihren Code entworfen haben. –

Antwort

2

Ja, es ist plausibel, dass Ihr Rückgabewert durch einen Maximalwert begrenzt ist. Dieses Maximum ist entweder die BYTE Grenze von 255 oder die WORD Grenze von 65536 mich, warum, Teil für Teil Lassen Sie erklären:

mov inputHandle, eax 
invoke ReadConsoleA, inputHandle, addr buffer, bufSize, addr bytes_read,0 
sub bytes_read, 2 ; -2 to remove cr,lf 
mov ebx,0 

mov al, byte ptr buffer+[ebx] 
sub al,30h 
add [actualNumber],ax 

In diesem Teil, den Sie fordern eine Win32 API Funktion, die immer den return Wert in der registrieren EAX. Nach der Rückgabe ordnen Sie die unteren 8 Bit des 32-Bit-Rückgabewertes byte ptr buffer+[ebx] zu, davon 30h. Dann haben Sie MOV die 8-Bit, die Sie gerade in AL geändert haben und die 8-Bit aus dem Rückgabewert in AH als Block AX zu einer WORD Variable von add [actualNumber],ax. So AH stammt aus dem EAX Rückgabewert und ist ganz von undefined. Sie können glücklich sein, wenn es 0 ist, aber das sollte nicht angenommen werden.

Das nächste Problem ist die folgende Unterroutine:

getNext: 
    inc bx 
    cmp ebx,bytes_read 
    jz cont 
    mov ax,10 
    mul [actualNumber] 
    mov actualNumber,ax 
    mov al, byte ptr buffer+[ebx] 
    sub al,30h 
    add actualNumber,ax 
    jmp getNext 

Sie bewegen sich die Dezimalbasis 10 zum WORD Register AX und multiplizieren sie mit der WORD Variable [actualNumber]. So weit, ist es gut. Aber das Ergebnis eines 16-Bit * 16-Bit MUL wird im Registerpaar AX:DX (niedriger: höher) zurückgegeben. Also Ihre mov actualNumber,ax nur MOV s die unteren 16-Bits zu Ihrer Variablen (DX wird ignoriert, Begrenzung Ihres Ergebnisses auf result % 65536). Ihr maximal mögliches Ergebnis ist MAX_WORD = 65535. Alles andere würde Ihnen nur den Modulo in AX geben.

nach dem mov al, byte ptr buffer+[ebx] Ihre überschreiben die unteren 8-Bits dieses Ergebnis mit dem BYTE durch buffer[ebx] zeigte und dann 30h davon subtrahieren. Denken Sie daran: Die höheren 8 Bits des Ergebnisses verbleiben immer noch in AH, die höheren 8 Bits von AX.

Dann fügen Sie diesen Wert (re) zur Variable actualNumber mit add actualNumber,ax hinzu. Lassen Sie mich diese letzten beiden Absätze kondensieren:

Operation      |  AX  | 
           | AL   AH | 
mov actualNumber,ax    | ................ | 
mov al, byte ptr buffer+[ebx] | ........  AH | 
sub al,30h      | ....-30h  AH | 
add actualNumber,ax    | ................ | 

Also, Sie ändern die unteren 8 Bits von AX durch AL und fügen Sie dann die höheren 8 Bits von actualNumber/AH sich - effektiv AH verdoppeln und dann Zugabe dies actualNumber wie folgt aus:

actualNumber = 256 * (2 * AH) + (byte ptr buffer[ebx]-30h)  ; I doubt you want that ;-) 

diese Probleme können einige Abweichungen vom gewünschten Ergebnis führen.

+0

Vielen Dank für Ihre Hilfe, aber ich verstehe nicht actualNumber = 256 * (2 * AH) + (Byte ptr Puffer [ebx] -30h) – dummieadam

+0

@dummieadam: Es ist ziemlich einfach: 'AX' ist (256 * AH) + AL. Oder in einer anderen Notation:' AX = AH * 256 + AL'. Um es anders auszudrücken: Ein 16-Bit-Wert wie 'AX' besteht aus zwei 8-Bit-Werten (' AH' und 'AL') und die" höheren "8-Bits werden von 2^8 =" gewichtet " 256. Also 'AX (16-Bit) = AH (8-Bit) * 256 + AL (8-Bit)'. – zx485