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 ausgeben

    Muss 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 ""abgeschlossen,dh.alsoquasi"" abgeschlossen, dh. also quasi ""-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
    9300

    counter 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 ds

    Das ergibt leider, zumindest fuer mich, ueberhaupt keinen Sinn.


Anmelden zum Antworten