Problem bei Einlesen von Zeichen



  • Also ich bin nun etwas weiter vorgestoßen und hänge gerade beim Einlesen fest. Dieser Code:

    TITLE Programmbibliothek
    MODEL SMALL,CPP
    IDEAL
    P386
    STACK 1024
    
    DATASEG
            cHeadline_01 db  '===========================================',0Ah,0Dh,'$',00h
            cHeadline_02 db  'Programmbibliothek 1.0.0 (c) by Kevin Jakob',0Ah,0Dh,'$',00h
            cText_01 db      'Bitte geben Sie ihren Namen ein : $',00h
            cInput db        32h
                   db        00h
            db 54 DUP        (?)
    
    CODESEG
    start:  
            STARTUPCODE
                 call WriteText,OFFSET cHeadline_01                         
                 call WriteText,OFFSET cHeadline_02
                 call WriteText,OFFSET cHeadline_01
                 call WriteText,OFFSET cText_01
                 mov ah,0Ah
                 lea dx,[cInput]
                 int 21h
                 mov es,dx
                 mov di,SIZE cInput
                 dec di
                 mov al,'$'
                 stosb
                 call WriteText,OFFSET cInput
                 call ExitProg
            EXITCODE
    
            PROC WriteText near Output:word
                 mov ah,09h
                 mov dx,[Output]
                 int 21h        
                 ret
            ENDP 
    
            PROC ExitProg
                 mov ah,04Ch
                 int 21h
                 ret
            ENDP
    END start
    

    funktioniert nicht. Ich weiß nichtmal ob etwas eingelesen wird, jedoch habe ich eher ein Problem mit dem Anhängen des '$'. Wo liegt mein Denkfehler?

    Das FAQ hat mir dabei nicht wirklich weitergeholfen

    EDIT:
    Der Assemblierer ist TASM!



  • bin den code mal durchgegangen und hab mich zuerst hier schlau gemacht:
    http://www.fh-wedel.de/~bek/asm/int21.html#int210a

    wie im link beschrieben, wird der offset des puffers in dx geschrieben. an dieser position steht dann auch die größe des puffers, also für wie viele zeichen er platz bietet. nach dem interrupt steht in der nächsten adresse die tatsächliche anzahl an zeichen/bytes die eingelesen wurde. ich würde dann zuerst platz für 32h (50) zeichen reservieren, wobei du den kompletten block mit '$' initialisierst.

    cInput db 32h dup ('$')
    

    damit das letzte zeichen (stringende) beim einlesen nicht überschrieben wird, gibst du dem interrupt ein zeichen weniger an

    mov ax, 31h
    mov bx, offset cInput
    mov [bx], ax
    

    (ich glaube den blöden umweg muss man so gehn)
    das sollte jetzt nach startupcode folgen, wobei warscheinlich auch noch das enter hintendran gehängt wird (habe da 2 widersprüchliche links gefunden), also u.u. nur eine 30h reinschreiben. wenn jetzt der text im puffer steht musst noch ein enter ausgeben (10, 13) da sonst die zeile "bitte geben Sie ihren Namen ein:" überschriben wird. hab da mal sowas gemacht:

    proc endl near
    push ax
    push dx
    mov ah, 02h
    mov dl, 13
    int 21h
    mov dl, 10
    int 21h
    pop dx
    pop ax
    ret
    endp endl
    

    nach dem enter kannst du den string direkt ausgeben, ohne noch ein '$' anhängen zu müssen. bei einem uninitialisierten block dürftest du aber so an das letzte zeichen drankommen

    mov bx, offset cInput+1
    add bx, [bx]
    

    (ungetestet)

    mich würde aber noch eins interessieren: was willst du mit zeile 12/13 bezwecken?



  • Naja ich hatte gelesen das bei int21h Funktion 0Ah einen sozusagen formatierten string erwartet, also das erste Byte enthält die Zeichen, die eingelesen werden können, das zweite Byte die tatsächlich eingelesene Anzahl. Daher hab ich das so gemacht und dann hinten dran noch einen speicherbereich mit 50 Zeichen, naja hab ich vielleicht falsch irgendwo aufgeschnappt, zumindest diese Schreibweise...

    EDIT:
    So habe jetzt den String schonmal ordnungsgemäß formatiert, hoffe ich zumindest. Folgender Code:

    TITLE Stringtest
    IDEAL
    P386
    MODEL SMALL
    STACK 1024
    
    DATASEG
            cOutput db 'Geben Sie ihren Namen ein : $'
            cInput  db 07h,00h,010h dup (' '),'Test',0Dh,0Ah,'$'   
    CODESEG
    start:
            mov ax,@data
            mov ds,ax
    
            mov ah,09h
            lea dx,[cOutput]
            int 21h
    
            mov ah,0Ah   
            lea dx,[cInput]
            int 21h
    
            mov ah,02h
            mov dl,0Dh
            int 21h
            mov dl,0Ah
            int 21h
    
            mov ah,09h
            lea dx,[cInput]
            int 21h
    
            mov ax,4C00h
            int 21h
    END start
    

    Nun mein problem, er liest zwar aus dem 1. Byte von cInput, wie viele Zeichen man eingeben kann, jedoch landet davon nichts in cInput selbst, wenn ich also(wie im Code zu sehen) das dann ausgeben lasse, so steht dann nur das Test, dann der Zeilenumbruch und fertig. Was fehlt noch?



  • Kevinus schrieb:

    Naja ich hatte gelesen das bei int21h Funktion 0Ah einen sozusagen formatierten string erwartet,

    ne. es wird einfach nur der ascii-code der zeichen in einem puffer gespeichert, wobei das problem ja nicht an der formatierung lag.

    Kevinus schrieb:

    also das erste Byte enthält die Zeichen, die eingelesen werden können, das zweite Byte die tatsächlich eingelesene Anzahl.

    ja ist ja soweit auch korrekt, bzw. siehe link dort stehts auch. das erste zeichen ist ja die startadresse, also praktisch das element mit dem index 0 und dort soll auch die größe des speicherblocks stehn.

    Kevinus schrieb:

    Daher hab ich das so gemacht und dann hinten dran noch einen speicherbereich mit 50 Zeichen

    ja genau, aber das hab ich nicht verstanden. warum teilst du (wie jetzt auch wieder) den speicher auf? und du brauchst noch ein enter vor der ausgabe. der cursor steht nämlich immer noch in der zeile "bitte namen eingeben" und das wird dann überschrieben.

    Kevinus schrieb:

    Nun mein problem, er liest zwar aus dem 1. Byte von cInput, wie viele Zeichen man eingeben kann

    wie soll er das lesen? du schreibst es ja gar nicht rein. hier mal ein code der sich mit dem tasm problemlos assemblieren lassen sollte.

    TITLE Stringtest
    IDEAL
    P386
    MODEL SMALL
    STACK 1024
    
    DATASEG
            cOutput db 'Geben Sie ihren Namen ein : $'
            cInput  db 32h dup ('$')   
    CODESEG
    start:
            mov ax, @data
            mov ds,ax
    
            mov bx, offset cInput	       
            mov ax, 30h                 ; zur sicherheit wegen dem enter
            mov [bx], ax                ; beim mov befehl sind nicht alle kombinationen möglich, deshalb der umweg.
    
            mov ah, 09h
            mov dx, offset cOutput
            int 21h
    
            mov ah, 0Ah   
            mov dx, offset cInput
            int 21h
    
            call endl					; newline wird ausgegeben
    
            mov ah,09h
            mov dx, offset cInput+2		; die ersten beiden bytes sind ja schon belegt.
            int 21h
    
            mov ax, 4C00h
            int 21h
    
            proc endl near
    			push ax
    			push dx
    			mov ah, 02h
    			mov dl, 13
    			int 21h
    			mov dl, 10
    			int 21h
    			pop dx
    			pop ax
    			ret
    		endp endl
    
    END start
    

    ob du jetzt nur 2 oder 20 zeichen eingibst, das folgende is immer ein ',alsostringende.dasmaximumistjaauf30hbegrenzt(zeile17),dannkommtnochmaximaldasenter(ascii13)unddasletzte', also stringende. das maximum ist ja auf 30h begrenzt (zeile 17), dann kommt noch maximal das enter (ascii 13) und das letzte '' und dann is schluss.



  • Aber auch bei Daniel's Homepage steht doch:
    Das erste Byte des Puffers gibt an, wie viele Zeichen (inklusive des Carriage Return am Ende) der Puffer maximal aufnehmen kann. Es muß von dem Programm vor Aufruf der Funktion in den Puffer eingetragen werden, damit die Funktion weiß, wie viele Zeichen sie maximal einlesen darf.

    In die Speicherstelle 1 trägt DOS nach Beendigung der Eingabe die Anzahl der eingelesenen Zeichen inklusive des Carriage Return ein.

    Ab der Speicherstelle 2 befinden sich nach der Beendigung der Funktion die eingelesenen Zeichen.

    MMm deswegen dachte ich, ich muss das erste Byte mit der Anzahl der zeichen, die eingelesen werden können, belegen und das zweite Byte mit 0, wo dann eingetragen wird, wie viele Zeichen eingelesen wurden, ab 3. Byte folgt dann die eingelesene Zeichenkette, hab ich da was falsch verstanden?

    Du lädst in den bx register die Anzahl der Zeichen, was bringt das? Greift den der Einleseinterrupt auf bx überhaupt zu, weil auf Daniel's Homepage finde ich kein Wort über den bx register, im Zusammenhang mit diesem Interrupt 0Ah



  • Kevinus schrieb:

    Aber auch bei Daniel's Homepage steht doch:
    Das erste Byte des Puffers gibt an, wie viele Zeichen (inklusive des Carriage Return am Ende) der Puffer maximal aufnehmen kann. Es muß von dem Programm vor Aufruf der Funktion in den Puffer eingetragen werden, damit die Funktion weiß, wie viele Zeichen sie maximal einlesen darf.

    Stimmt ja so auch.

    Kevinus schrieb:

    In die Speicherstelle 1 trägt DOS nach Beendigung der Eingabe die Anzahl der eingelesenen Zeichen inklusive des Carriage Return ein.

    Ab der Speicherstelle 2 befinden sich nach der Beendigung der Funktion die eingelesenen Zeichen.

    War vielleicht ein Missverständnis. mit index 0 meinte ich die erste Speicherstelle, ja. dannach in der folgenden die tatsächliche anzahl einegelesener zeichen.

    Kevinus schrieb:

    MMm deswegen dachte ich, ich muss das erste Byte mit der Anzahl der zeichen, die eingelesen werden können, belegen und das zweite Byte mit 0.

    aber durch die zahlen zwischen den kommata weist du doch den speicherstellen keine werte zu. du reservierst doch nur speicher und vor allem wie kommst du auf die 0? meinst du da addiert die funktion eine zahl zum bisherigen wert der an dieser speicherstelle steht? ne, da kann drinstehn was will.

    Kevinus schrieb:

    ab 3. Byte folgt dann die eingelesene Zeichenkette, hab ich da was falsch verstanden?

    wenn man das, so wie ich, als array betrachtet isses das zweite element 😉 .
    aber ich weiss was du meinst, also nein, du hast es schon richtig verstanden.

    Kevinus schrieb:

    Du lädst in den bx register die Anzahl der Zeichen, was bringt das? Greift den der Einleseinterrupt auf bx überhaupt zu, weil auf Daniel's Homepage finde ich kein Wort über den bx register, im Zusammenhang mit diesem Interrupt 0Ah

    der greift nicht auf bx zu. aber wenn ich den kompletten block mit '' initialisiere, dann steht im ersten ja immer noch nicht die größe des blocks sondern ein '' (ascii wert 36, es soll aber eine 50 (hex 32h) drinstehn). also muss ich dieser speicherstelle noch extra einen wert zuweisen. und das ist dann die größe, nur akzeptiert der mov befehl eben nicht jede beliebige kombitnation. ich kann anscheinend nicht sowas schreiben

    mov speicher, wert
    

    und muss deshalb den umweg über das register gehn.

    hat denn mein code bei dir geklappt?



  • Joar hat geklappt ich hatte einen Denkfehler:
    Ich dachte mit

    cInput db 07h,00h,010h dup (' '),'Test',0Dh,0Ah,'$'
    

    kann ich einfach wie normal Zeichen aneinander hängen, was ja auch geht bei normalen db's. Jedoch kann ich dann natürlich nicht mittendrin mit dup so und so viele Byte reservieren. Da hat er dann was verkackt *G*. Aber jetzt weiß ich wie. Mit bx hat sich auch erledigt, war ebenfalls ein Logikfehler von mir. Thx für die Hilfe.


Anmelden zum Antworten