Zahlen hoch zählen lassen
-
Hallo ich versuche gerade mit TASM Zahlen von 1 bis 3 hochzählen zu lassen.
Aber jetzt werden mir die ja nur als Ascii Zeichen ausgeben.Muss man die jetzt irgendwie in Dezimal umrechnen oder ist mein Ansatz falsch ?
.model small .stack 900h .data zahl DB 0,"$" endl db 10,13,"$" .CODE start: mov ax,@data mov ds,ax mov cx,3 mov dx,offset zahl i: add zahl,1 mov ah,9h int 21h Loop i mov ah, 4ch int 21h END start
-
Noe, dein Ansatz ist so weit in Ordnung. Um integer (oder andere Zahlenformate) in DOS mit int 21h ausgeben zu koennen, musst du sie nur erst in einen String umwandeln.
Fuer einstellige Zahlen (zB. Ziffern 0 bis 9) ist das allerdings denkbar einfach umsetzbar:
Die ASCII-Zeichen "0" bis "9" haben die Zahlenwerte 30h bis 39h. Die einfachste Loesung, das von dir gewuenschte Verhalten zu erreichen waere also, wenn du in "zahl" von 30h anfaengst zu zaehlen.Allgemein zur Umwandlung int->String:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-238084.html
und
http://www.c-plusplus.net/forum/viewtopic-var-t-is-236735.html
-
ok ty werd ich morgen mal versuchen.
-
Danke das funktionierte schonmal.
Aber wie läuft das dann wenn ich höher als 9 Zählen möchte ?
Hier hast du geschrieben:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-236735.html
int->string:
Das Prinzip ist eigentlich immer das Gleiche, egal, welche Zahlenbasis (binaer, oct, dec, hex...) du verwenden willst:
Dividiere deine Zahl wiederholt so lange durch die Basis (zB. 10 fuer dezimal), bis der Quotient 0 wird.
Der x86-Befehl "div" fuehrt eine Division von ax, ax:dx oder eax:edx durch den Operanden, den Divisor durch (je nachdem, ob dieser 8, 16 oder 32Bit breit ist) und speichert den Quotient in ax (al, ax oder eax) und den Rest in dx (ah, dx oder edx).Der Rest jeder Division ist dann eine Stelle der Zahl (hier Werte von 0-9). Die musst du noch in ein lesbares Zeichen umwandeln, zB. fuer ASCII, indem du 30h dazu addierst (oder "veroderst") - siehe eine Tabelle des ASCII-Zeichensatzes.
Bei diesem Vorgang kommen die Ziffern, wie du feststellen wirst, in umgekehrter Reihenfolge heraus, also zuerst die 1er-Stelle, dann 10er, usw.
Du kannst also nun deinen String entweder direkt mit den berechneten Resten von hinten noch vorn befuellen, oder du parkst die Ziffern auf einem Stapel und "pop"st sie von dort in deinen String, um die Reihenfolge umzudrehen. Dazu bietet es sich an, den normalen x86-Stack zu benutzen und mit zu zaehlen, wie viele Ziffern du raufpackst.
Am Ende noch das "$" an den String haengen und du kannst ihn mit Funktion 09h ausgebenMuss ich das dann auch so machen wenn ich höher als 9 Zählen möchte ?
-
Ja.
Das ist das allgemeine Prozedere zum Umwandeln von Integer zu String - bei mehrstelligen Zahlen kommst du da nicht umhin.
-
Najut dann werd ich mal schauen ob ich es hin bekomme hab atm leider nicht so viel Zeit.
Aber Danke erst mal.
-
Hallo ich hab mal etwas Zeit gefunden und mich mal an der Sache versucht einen int zahl in einen string umzuwandeln.
Bei diesem Vorgang kommen die Ziffern, wie du feststellen wirst, in umgekehrter Reihenfolge heraus, also zuerst die 1er-Stelle, dann 10er, usw.
Den einer bekomme ich ja schon mal ausgeben aber wie krieg ich jetzt den Zehner oder ist mein Ansatz falsch ?
.model small .stack 900h .data wert DB ? ,"$" .CODE start: mov ax,@data mov ds,ax mov cx,1 a: mov ax,15 ; die 15 soll in einen string umgewandelt werden mov bl,10; dividiert ax / bl al = ergebniss ah = rest div bl mov wert,al add wert,30h mov wert ,ah add wert,30h mov dx,offset wert mov ah,9h int 21h Loop a mov ah, 4ch int 21h END start
-
Fuer ein tieferes Verstaendnis der ganzen Sache koenntest du erstmal allgemein bei folgenden Fragen ansetzen:
Wie wird ein ASCII-Zeichen (char) gespeichert? Und wie dann ein String?Konkret in deinem Code betrifft das erstmal die folgenden Stellen:
Was macht deiner Meinung nach das hier:wert DB ? ,"$"
Und dann nochmal scharf hierueber nachdenken:
mov wert,al add wert,30h mov wert ,ah add wert,30h
-
Hallo ich habs mir mal angeschaut.
wert DB ? ,"$' <--- eine uninitalisierte variable welche null terminiert wird DB = Byte/Char größe 8 bits mhmh 8 bit aber ich hab ja mehr als 8 bit oder ?
mov wert,al ; add wert,30h <-- das ist überflüssig ich muss ja erst weiter untern die 30h dazu rechnen ka wie das da hin kam .. mov wert ,ah add wert,30h
.model small .stack 900h .data var1 DB 65,"$" ; ASCII Code 65 in der Variable var1 abspeichern 65 = A var2 DB "hallo$" ; den string hallo in der Variable var2 abspeichern .CODE start: mov ax,@data mov ds,ax mov dx,offset var1 mov ah,9h int 21h mov dx,offset var2 mov ah,9h int 21h mov ah, 4ch int 21h END start
-
Ich glaub ich hab es jetzt zumindest wird die 15 ausgeben.
Ist das so richtig ?
.model small .stack 900h .data wert DB ? , "$" ; DB anstatt DW ?? var DB ? ,"$" .CODE start: mov ax,@data mov ds,ax mov cx,1 a: mov ax,15 ; die 15 soll in einen string umgewandelt werden mov bl,10; dividiert ax / bl al = ergebniss ah = rest div bl mov var , al mov wert ,ah add wert,30h add var,30h mov dx,offset var mov ah,9h int 21h mov dx,offset wert mov ah,9h int 21h Loop a mov ah, 4ch int 21h END start
-
Mhhm mov cx,1 und die Schleife brauch ich gar nicht.
-
counter schrieb:
wert DB ? ,"$' <--- eine uninitalisierte variable welche null terminiert wird DB = Byte/Char größe 8 bits mhmh 8 bit aber ich hab ja mehr als 8 bit oder ?
Nicht ganz. Das ist eine uninitialisierte Byte-Variable, gefolgt von einem Byte, das das Zeichen "$" enthaelt. (dadurch, dass ein initialisiertes Byte folgt, wird die uninitialisierte Variable praktisch uebrigens zu einer initialisierten 0).
Damit kannst du also vor dem Terminierungszeichen genau ein Zeichen, also eine Ziffer darstellen.
... Logische Folgerung: Wenn du mehr Zeichen ausgeben willst, musst du entweder mehr Platz - mehr Bytes - fuer deinen String reservieren, oder deinen Ein-Zeichen-String mehrmals hintereinander befuellen und ausgeben. Ersteres liegt wohl naeher.Mehrere Bytes kann man in TASM einfach wie folgt reservieren:
Wert db 10 dup (?) ; reserviert 10 uninitialisierte Bytes
counter schrieb:
mov wert,al ; add wert,30h <-- das ist überflüssig ich muss ja erst weiter untern die 30h dazu rechnen ka wie das da hin kam .. mov wert ,ah add wert,30h
Nein, das ist nicht ueberfluessig! Du musst die 30h auf jede einzelne Ziffer addieren.
Wenn du mal genau hinschaust, sollte dir auffallen, dass du hier zuerst die Zehnerstelle aus al nach wert schiebst und 30h draufaddierst - soweit ok.
Dann ueberschreibst du jedoch in den naechsten 2 Zeilen deine gerade nach "wert" kopierte Zehner-Ziffer mit der Einer-Stelle in ah.
Das sollte dir auffallen: Du greifst hier zweimel direkt hintereinander auf das selbe (in diesem Code das einzige) Zeichen deines Strings zu.counter schrieb:
Ich glaub ich hab es jetzt zumindest wird die 15 ausgeben.
Ist das so richtig ?
.model small .stack 900h .data wert DB ? , "$" ; DB anstatt DW ?? var DB ? ,"$" .CODE start: mov ax,@data mov ds,ax mov cx,1 a: mov ax,15 ; die 15 soll in einen string umgewandelt werden mov bl,10; dividiert ax / bl al = ergebniss ah = rest div bl mov var , al mov wert ,ah add wert,30h add var,30h mov dx,offset var mov ah,9h int 21h mov dx,offset wert mov ah,9h int 21h Loop a mov ah, 4ch int 21h END start
Diese Panne umgehst du hier, indem du fuer jede Ziffer einen eigenen mit "$" terminierten String befuellst.
counter schrieb:
Mhhm mov cx,1 und die Schleife brauch ich gar nicht.
Richtig. Nur zum Konvertieren brauchst du diese Schleife hier nicht.
Jetzt waere es noch sinnvoll, wenn du deine 2 Ziffern in einem String unterbringen koenntest. Dazu fehlst dir scheinbar noch die Info, wie du in TASM quasi auf Arrays zugreifen, bzw. Offsets zu Labels zugreifen kannst. Also mal ein kleines Beispiel dazu:
.model small .stack 900h .data Ausgabe db 2 dup (0) db "$" ; Variablen landen exakt in der im Quellcode angegebenen Reihenfolge im Programm und damit im Speicher. ; dh. es wird hier db 0, 0, "$" im RAM stehen. .CODE start: mov ax,@data mov ds,ax mov ax,15 ; die 15 soll in einen string umgewandelt werden mov bl,10; dividiert ax / bl al = ergebniss ah = rest div bl mov [wert], al ; eckige Klammern kennzeichnen Zugriff konkret auf Speicher ;statt abstrakt "Variablen" mov [wert + 1], ah ; +1 meint Offset der Variable, kekennzeichnet durch das Label "wert" + 1, dh. das naechste Byte hinter dem Byte bei "wert". add byte ptr [wert],30h add byte ptr [wert + 1],30h ; Bei Zugriffen auf den Speicher musst du TASM jedoch mitteilen, wie gross denn der Bereich ist, auf den du zugreifen willst. ; dass passiert mit dem vorangestellten byte ptr (AFAIR, oder so aehnlich - ungetestet). ; stattdessen koenntest du natuerlich auch einfach direkt ein word auf wert addieren - mal drueber nachdenken, wie und warum das funktioniert...: ; add word ptr [wert], 3030h mov dx,offset wert mov ah,9h int 21h mov ah, 4ch int 21h END start
hth.
-
Ich hab das jetzt so gemacht und meine Zahl wird auch richtig ausgeben.
Als ich das mit
add byte ptr
und so gemacht habe wie aus deinem beispielt hat der PC nur gepiept und komsiche Zeichen ausgegeben.
Aber die Variable wert db "$" ist doch so richtig Null Terminiert oder ?
.model small .stack 900h .data wert1 db 10 dup (0) , "$" ; array für 10 zeichen .CODE start: mov ax,@data mov ds,ax mov ax,73 ;die 15 soll in einen string umgewandelt werden mov bl,10 ;dividiert ax / bl al = ergebniss ah = rest div bl mov wert1[0],al ;wert1 dort werden die ZEHNER der zahl gespeichert hier wird also die 7 drin gespeichert add wert1[0],30h ; ASCII wert eine eine dezimal zahl umwandeln mov wert1[1] ,ah ;wert2 dort werden die EINER der zahl gespeichert hier wird also die 3 drin gespeichert add wert1[1],30h ; ASCII wert eine eine dezimal zahl umwandeln mov dx,offset wert1 mov ah,9h int 21h mov ah, 4ch int 21h END start
2 Fragen habe ich noch:
1. Wie kann man 3 stellige Zahlen ausgeben lassen ?
.model small .stack 900h .data wert1 db 10 dup (0) , "$" ; array für 10 zeichen var db 73 , "$" .CODE start: mov ax,@data mov ds,ax mov ax,var ; Fehler: operand type do not match ; wie kann ich z.b. einen wert aus einer variable in ax reinschreiben ? ; das ist ja sowie bei mov ax,@data mov ds,ax da kann ich ; ja auch nicht einfach schreiben: mov as,@data das umgehe ich ja mit dem ds mov bl,10 ;dividiert ax / bl al = ergebniss ah = rest div bl mov wert1[0],al ;wert1 dort werden die ZEHNER der zahl gespeichert hier wird also die 7 drin gespeichert add wert1[0],30h ; ASCII wert eine eine dezimal zahl umwandeln mov wert1[1] ,ah ;wert2 dort werden die EINER der zahl gespeichert hier wird also die 3 drin gespeichert add wert1[1],30h ; ASCII wert eine eine dezimal zahl umwandeln mov dx,offset wert1 mov ah,9h int 21h mov ah, 4ch int 21h END start
-
mov ax,73 ;die 73 soll in einen string umgewandelt werden
73 nicht 15 sry.
-
counter schrieb:
Als ich das mit
add byte ptr
und so gemacht habe wie aus deinem beispielt hat der PC nur gepiept und komsiche Zeichen ausgegeben.
Kann ich nicht nachvollziehen. In dem Code war zwar ein Fehler: Das Label fuer den String war falsch benannt und das Board hat seit Ewigkeiten die Macke, bei Strings abschliessende " in ' zu verwandeln, aber sonst funktionierte der Code bei mir mit einfachem C&P fehlerfrei.
counter schrieb:
Aber die Variable wert db "$" ist doch so richtig Null Terminiert oder ?
Mach dir mal klar, was "Null Terminiert" ueberhaupt bedeutet: Etwas (ein String) wird mit (dem Wert / der Zahl) Null terminiert, also abgeschlossen.
Das ist ganz offensichtlich in deinen Codes nirgendwo der Fall: Hier sind die Strings immer mit dem Zeichen ""-terminiert.Dazu sollte man vielleicht noch etwas weiter ausholen:
Ein String ist allgemein eine beliebig lange Aneinanderreihung von einzelnen Zeichen, bzw. chars (hier ASCII-Codiert und jeweils 1 Byte breit).
Um mit Strings sinnvoll arbeiten zu koennen, musst du irgendwie bestimmen koennen, wie lang ein String eigentlich ist, bzw. wo er aufhoert.
Dazu gibt es im Prinzip 2 naheliegende Ansaetze:
1. Du speicherst die Laenge des Strings in einer Variable. In Pascal wurde das zB. so gemacht, dass direkt vor das erste eigentliche Zeichen eines Strings praktisch an die "0. Stelle" ein Byte gesetzt wurde, das die Laenge enthaelt.
2. Du legst einen bestimmten Code, praktisch also ein bestimmtes Zeichen, fest, welches das Ende des Strings markiert. In C und auch sonst nimmt man dazu praktischerweise das Zeichen mit dem Binaerwert 0 (dem ist auch kein lesbares Zeichen, bzw. einfach ein space zugeordnet). In deinem Code hier nimmst du stattdessen das Zeichen "$", um das Ende des Strings zu kennzeichnen - einfach, weil die DOS-Funktion 09h, die du zum Ausgeben des Strings auf dem Bildschirm benutzt das so erwartet.counter schrieb:
1. Wie kann man 3 stellige Zahlen ausgeben lassen ?
Was ist dir denn daran nicht klar?
Das Prinzip ist exakt das Gleiche wie fuer 2stellige Zahlen.
Falls du das Prinzip hinter der Sache nicht verstanden hast, bzw. dir noch nicht klar ist, warum du diese Division durch 10 ueberhaupt machen musst, kann ich dir nur empfehlen, die verlinkten Threads noch einmal aufmerksam durchzulesen.
Warum, wie und weshalb und selbst ein kompletter Beispielcode fuer "beliebig-stellige" Zahlen in C sind dort zu finden.counter schrieb:
var db 73 , "$" ;..... mov ax,var ; Fehler: operand type do not match ; wie kann ich z.b. einen wert aus einer variable in ax reinschreiben ?
Klar: Deine Variable ist vom Typ Byte und du versuchst einfach so ein word daraus zu lesen.
Im Grunde hast du jetzt 3 Moeglichkeiten, dieses Problem zu beseitigen:
1. du passt den Typ der Variable an: Mach ein word draus (dw)
2. du liest in ein passendes, 1 Byte breites Register (zB. al).
3. du sagst TASM explizit, dass du nicht mit einer Variablen arbeiten willst, sondern einen 1 word breiten Speicherzugriff beim Label "var" machen willst (zB. mov ax, word ptr [var])Mal davon ab: Das "$" hinter der 1 byte breiten Integer-Zahl 73 ist dort ziemlich deplatziert. Das brauchtest du bisher allein zum Abschliessen von Strings. Die 73 dort ist aber kein String, muss also auch nicht terminiert werden.
Was du da sonst gebastelt haettest, ist praktisch im Speicher byteweise betrachtet die Zahlen
73, 36
oder wortweise betrachtet die Zahl
9300counter schrieb:
; das ist ja sowie bei mov ax,@data mov ds,ax da kann ich
; ja auch nicht einfach schreiben: mov as,@data das umgehe ich ja mit dem dsDas ergibt leider, zumindest fuer mich, ueberhaupt keinen Sinn.