Übungsprogramm klappt nicht richtig
-
hey
ich wollte bisschen Üben und ein Programm schreiben, welches 5 Werte entweder addiert oder subtrahiert. Irvine32.inc stellt mir paar funktionen zum console input-output zur verfügung, wundert euch deswegen nicht (WriteString ReadHex etc.). Jedenfalls klappt alles soweit, aber wenn ich z. b. 5 mal 10 eingebe dann gibt es 80 als Ergebnis aus. Woran liegt das? Ihr könnt mir auch andere Sachen sagen die ich schlecht gemacht habe oder sagen was man besser machen könnte! DankeTITLE Calculator (Calculator.asm) INCLUDE Irvine32.inc .data addOrSubQ BYTE "Welcome! Do you want to add or subtract values? (1 = add, 2 = sub)", 0 promptMessage BYTE "Pls tell me 5 values!", 0 resultMessage BYTE "Here is the result: ", 0 againOrNotQ BYTE "Do you want to calculate again? (1 = yes, 2 = no)", 0 .data? values DD 5 DUP(?) addOrSubA DD ? result DD ? againOrNotA DD ? .code main PROC mov eax, 10 call SetTextColor ; chance color start:: call addOrSub call promptForValues call calculateResult back:: call printResult call againOrNot call WaitMsg exit main ENDP ; gives back the result (1 Or 2) to eaxreg addOrSub PROC mov edx, OFFSET addOrSubQ call WriteString call crlf call ReadHex ; read input mov addOrSubA, eax ret addOrSub ENDP promptForValues PROC mov edx, OFFSET promptMessage call WriteString call crlf call ReadHex mov values, eax call ReadHex mov [values + 4], eax call ReadHex mov [values + 8], eax call ReadHex mov [values + 12], eax call ReadHex mov [values + 16], eax call crlf ret promptForValues ENDP calculateResult PROC cmp addOrSubA, 1 JE addValues cmp addOrSubA, 2 JE subValues ret calculateResult ENDP addValues:: mov eax, values add eax, [values + 4] add eax, [values + 8] add eax, [values + 12] add eax, [values + 16] mov result, eax jmp back subValues:: mov eax, values sub eax, [values + 4] sub eax, [values + 8] sub eax, [values + 12] sub eax, [values + 16] mov result, eax jmp back printResult PROC mov edx, OFFSET resultMessage call WriteString mov eax, result call WriteInt call crlf ret printResult ENDP againOrNot PROC mov edx, OFFSET againOrNotQ call WriteString call crlf call ReadHex mov againOrNotA, eax cmp againOrNotA, 1 JE start ret againOrNot ENDP END main
-
Zur eigentlichen Frage:
Du liest dem Prozedurnamen "ReadHex" zufolge offenbar hexadezimale Zahlen (Basis 16, Ziffern 0-F) ein.
"WriteInt" scheint jedoch Zahlen dezimal (Basis 10, Ziffern 0-9) auszugeben.
Nun ist 10 hexadezimal gleich 16 dezimal. Dh. 5*10=50 hexadezimal ist 5*16=80 dezimal. Um Verwirrung vorzubeugen waere es also zweckdienlich, Zahlen mit der selben basis einzulesen und auszugeben.Noch allgemein:
In Assembler ist es idR. keine gute Idee, Prozeduren zur reinen Strukturierung zu benutzen. Das laeuft irgendwo dem Sinn und Zweck von Assembler zum Schreiben effizienter Programme entgegen.
Um den Code und das Prinzip der Prozedur uebersichtlich zu halten sollte man es auch vermeiden, zwischen Prozeduren mit normalen Sprungbefehlen zu wechseln.
So laesst du zB. auch mit jedem Sprung von "againOrNot" zum Label "start" die Ruecksprungadresse auf dem Stack liegen, was bei mehreren Wiederholungen zwangslaeufig irgendwann zu einem Stack-Ueberlauf fuehren wird.
Ich wuerde also vorschlagen, bis auf die Prozeduren aus der .inc-Datei saemtliche Prozeduren aus deinem Code zu entfernen und deren Funktionalitaet direkt hin zu coden.
-
vielen Dank Nobou T! Jetzt verwende ich ReadDec.
Und danke auch für die Tipps!
-
jetzt habe ich noch ein größeres Problem.
Ich soll mit ADC ( das ja das carry mitaddiert) 2 64 bit ints addieren und das Ergebnis zeigen.TITLE Chapter7Exercise (Chapter7Exercise.asm) INCLUDE Irvine32.inc .data op1 QWORD 18446744073709551615 op2 QWORD 18446744073709551615 result BYTE "The result is: ", 0 .data? sum DWORD 3 DUP(?) .code main PROC mov esi, offset op1 mov edi, offset op2 mov ebx, offset sum mov ecx, 2 ; number of dword clc ; clear carry L1: mov eax, [esi] adc eax, [edi] pushfd mov [ebx], eax add esi, 4 add edi, 4 add ebx, 4 popfd loop L1 adc WORD PTR[ebx], 0 popad mov edx, offset result call WriteString call crlf mov eax, [sum + 8] call WriteInt mov eax, [sum + 4] call WriteInt mov eax, sum call WriteInt mov eax, 2000 call Delay exit main ENDP END main
Leider steig ich da nicht mehr durch. Außerdem ist in sum kein richtiges Ergebnis. Könnte sich das bitte jemand anschauen?
-
habs jetzt nochmal mit einer anderen Version probiert. Es wird aber auch nicht das richtige ergebnis ausgegeben.
TITLE Chapter7Exercise (Chapter7Exercise.asm) INCLUDE Irvine32.inc .data op1 QWORD 18446744073709551615 op2 QWORD 18446744073709551615 result BYTE "The result is: ", 0 .data? sum DWORD 3 DUP(?) .code main PROC mov eax, DWORD PTR op1 ; low word of op1 mov ebx, DWORD PTR [op1+4] ; high word of op1 mov ecx, DWORD PTR op2 ; low word of op2 mov edx, DWORD PTR [op2+4] ; high word of op2 clc ; clear carry to be safe mov sum, eax ; low word op1 adc sum, ebx ; high word op2 add sum, ecx ; low op2 adc sum, edx ; high op2 mov edx, offset result call WriteString mov eax, sum call WriteDec mov eax, sum[4] call WriteDec mov eax, sum[8] call WriteDec ; sollte jetzt so aussehen als wäre es 1 zahl, da es nacheinander geschrieben wird. mov eax, 5000 call Delay ; sleep exit main ENDP END main
-
Das Prinzip ist, dass du nacheinander das 1. dword des 1. op mit dem des 2. op (beim 1. brauchst du auch noch kein adc, da der Uebertrag sicher 0 ist - so sparst du dir auch das clc) addierst und im 1. dword des Ergebnisses speicherst. Dann das 2. dword des 1. op mit dem des 2. op und den Uebertrag aus der 1. Addition dazu im 2. dword des Ergebnisses. Zuletzt brauchst du nur noch den Uebertrag der letzten Addition (also das Carry-Flag CF) an das Ergebnis anhaengen. Geht zB. indem du auf das dritte (ein Byte wuerde hier reichen) ein adc mit 0 machst.
Das sieht im Prinzip im 1. Code auch ganz gut umgesetzt aus und das Ergebnis sollte so weit ich das mit diesem Schnipsel beurteilen kann auch stimmen. Bleibt fuer diesen Code eigentlich nur anzumerken, dass das "popad" in z. 34 dort IMHO nichts zu suchen hat und dass man so kurze Schleifen (weniger als 4 Durchlaeufe) besser direkt ausrollen sollte (wie du es in deinem?, dem 2. Code versucht hast).
Beim 2. Code kommst du jedoch irgendwie mit den einzelnen Summanden total durcheinander und addierst auch immer nur wirr auf das 1. dword der Summe drauf. Da kann nichts sinnvolles bei herauskommen.
Weiter kannst du einen integer nicht sinnvoll als Dezimalzahl ausgeben, indem du ihn auf diese Weise Stueck fuer Stueck hintereinander konvertierst. Das geht wohl nur mit Zahlensystemen, deren Basis eine Potenz von 2 ist. Also zB. hexadezimal wie im 1. Code.Beispiel:
Ein word aus 2 Bytes (01 01) wird derart byteweise konvertiert.
Ergebnis dezimal:
jeweils 1 -> 11 -> falsch. sollte 257 sein.
Ergebnis hexadezimal:
jeweils 01 -> 0101 -> stimmt.Beachte beim Ueberpruefen des Ergebnisses des 1. Codes auch, dass die beiden Summanden aus irgendeinem Grund dezimal angegeben sind.
-
danke! Hab es verstanden.