あなたは何が起こるか、デバッガで確認する必要があります。
あなたは、あなたが最初のプロンプトで「ヘレナ」を入力した後、string1
アドレスのメモリ内容があることがわかります希望の場合:
32 07 48 65 6C 65 6E 61 0D 24 24 24 24 ...
これらのデータについて重要なことは、また、CR(と呼ばれる値0D
れますキャリッジリターン)をアドレスstring1 + 2 + 7 - 1
(文字列データに到達するために+2、+ 7は入力の長さ、-1は最後の文字に戻る)に移動します。
他の2つの入力についても同じことが適用されます。
あなたが最終ラインの出力を開始しますたら、画面上で書きます:
You are Helena
、そこにバックラインの先頭にBIOSカーソルを返します。最初のCRは、来るが、それは続いていませんLF(0Ah
)、カーソルは1行下にも移動せず、代わりに2行目の出力が行の先頭を上書きします。
は修正するには:ユーザによって入力されたそれぞれの名前を表示する先を、実行します。
mov ah, 09
mov dx, offset string1 + 2 ;displays inputted "first name"
movzx bx, byte ptr [dx-1] ; bx = length of input
mov byte ptr [bx + dx - 1], '$' ; overwrite last input char (most likely CR) with '$'
int 21h
(リアルモードは、モード[bx + dx -1]
をアドレッシングをサポートしていない場合、単にadd bx,dx
を行うと...その後[bx-1]
を使用してマイメモリがぼやけている、私はもっと多くのプロテクトモードx86アセンブリをやっていました。アドレシングモードははるかにリラックスして普遍的です)。
もしも8086が偶数をもたない場合、xor bx,bx
mov bl,[dx-1]
は同じことをすることができます(メモリから読み込み、ゼロに伸ばす)。
EDIT:実際にあなたが名前の間にスペースを入れて、むしろSPACE ' '
でその最後の文字を上書きすることがあります...とstring3
あなたが新しいため、その終わりCR + LFペアで書くことmov word ptr [bx+dx-1],0A0Dh
でそれを上書きすることで、できるだけ長い入力(全部で50文字)でメモリの上書きを避けるために、string3
バッファの後ろにもう1バイトを置くべきです。
EDIT:いくつかのより多くのコメント...
は、それはインターネットの時代だ任意のブック
を持っていません。 8086(おそらくemu8086にあると思います)を教えることは、それ自体が残酷な冗談のようなものです。そして、この知識は、今後のプログラミング関連の新たな視点を与えるでしょう。あなたはemu8086のチュートリアルをいくつか試してみることができるはずです(ただし、私は質についてはわかりませんが、いくつかの質問で判断すると基本的なチュートリアルしか見つけるのは難しいですが...)それは個人的な使用のための電子形式で読むために、それは非常に徹底的で詳細です...しかし、巨大(あなたのコースが本当に悪い場合は、まだ16b DOS版をチェックしたいかもしれませんし、あなたの側で適切な研究が必要とされる領域)を特定する。
を、私は文字列はあなたがやった
スタックにプッシュされている方法に問題があると感じていますあなたのコードのどこにでもスタックに触れないでください...このライトであなたのコメントはかなり恐ろしく聞こえるでしょう、それは200-300ページを読むことを意味しても、おそらく本当にその本を掘るべきです。結局のところ、あなたは "緊急"を使用しなかったので、アセンブリやコンピュータアーキテクチャの基本に追いつくのに数カ月の時間がかかりそうです。
「SPACEのEDIT」のFIX:
しかし、あなたは、スペースでその最後の文字を上書きするときに、ユーザーが50文字長い名前を入力した場合、その後、名前は何より'$'
は終了しませんので、あなたがすべきむしろ、このように、それらを超えて固定ターミネータを持っているあなたのバッファを定義します:
string1 db 50,0,51 dup ('$') ; after 50 byte buffer there's one more '$'
これは、ASMプログラミングにおける最も困難な部品の一つである、誤ったデータの定義に起因する、任意のバッファ/スタックオーバーフローのバグを回避するために、そして安全でない使い方メモリの。デバッガの最小/最大入力で常にコードをテストし、メモリ内容を見て、期待どおりに動作するかどうか、または予期しないメモリの上書きが発生したかどうか、そしてどこでそれが起こるかを確認してください。場合たとえば、あなたは、いくつかのコーナーケースの入力がなくなってFF
バイト作られたデバッガで見た場合、あなたは(あなたがあなたの元の間違ったを持って知っている次に
string1 db 50,0,51 dup ('$')
db 0FFh
msg2 db 0ah, 0dh, "Enter last name: $"
:あなたはまた、同様に、バッファ間のいくつかのガード値を定義することもできます最初のバイトは52、ユーザーは52文字の長い名前を入力します)。
(リアルモードでは有効ではありません、元のモード[dx]
に取り組むことを提案)リアルモードで有効な8086のコードと修正:
は、コードの末尾に最初の手順を追加し、最後に上書きされます入力された文字+パスカルのような文字列(長さが先に文字列自体のバイトのメモリに保存されている)の1以上のバイト:
; input:
; dx = address of string ([dx-1] must contain length of string)
; ax = two chars to be written at the end of string (al = first, ah = second)
changeEndOfInputString:
push si ; preserve original si and bx values
push bx
mov si,dx ; use SI for addressing in real mode
xor bx,bx ; bx = 0
mov bl,[si-1] ; bx = (zero extended) string length
mov [si+bx-1],ax ; overwrite last inputted char + one more
pop bx ; restore bx and si and return
pop si
ret
そして今、名前文字列の表示には、スペースや改行を追加するためにそれを使用します必要です。
;=====output======
;display "You are "
mov ah, 9
mov dx, offset msg4
int 21h
;display inputted "first name" with space added
mov dx, offset string1 + 2
mov ax, 2420h ; 20h = ' ', 24h = '$' (ASCII encoding)
call changeEndOfInputString
mov ah, 9
int 21h
;display inputted "middle name" with space added
mov dx, offset string3 + 2
mov ax, 2420h ; 20h = ' ', 24h = '$' (ASCII encoding)
call changeEndOfInputString
mov ah, 9
int 21h
;display inputted "last name" with CR+LF added
mov dx, offset string2 + 2
mov ax, 0A0Dh ; 0Dh = CR, 0Ah = LF (DOS "new line")
call changeEndOfInputString
mov ah, 9
int 21h
そして、あなたの文字列バッファがこれらの変更に対処するために最後に追加バイトを持っていることを確認してください。
string1 db 50,0,51 dup ('$') ; first name buffer
string2 db 50,0,52 dup ('$') ; last name buffer
string3 db 50,0,51 dup ('$') ; middle name buffer
場合、ユーザは、完全な50個の文字を入力するため、「姓」のバッファは、52「$」を必要とします50番目と51番目の文字はCR + LFに上書きされるので、52番目の '$'はint 21h,9
サービスの文字列ターミネータとして保存します。
入力は' '+'$'
で変更されるので、最初の+中間の名前バッファは51で$ 'です。したがって、50文字の入力の場合、51番目の文字は変更後も' $ 'に設定されたままです。それは入力編集のために有効であり、そしてあなたが任意の有効なを提供していませんどのくらいのバッファコンテンツのDOSを伝える、実際にいくつかのDOSバージョンでの入力値だから
はまた、?
、0
に0Ah
サービスバッファの2番目のバイトを設定されていませんバッファ内の呼び出し前の文字列。
そして最後の注意:
crlf db 0ah, 0dh, '$'
これはLF + CR(間違った順序)で、DOS "新しい行が" CR + LFである必要があり、期待通りすなわち13、10 10、13は主に動作しますしかし、組み立ての世界では、これは何らかの形でバグですが、それは大きな影響を及ぼさないことは幸いです。 (すべての文字列定義で間違っています)。
だから私はbxに置き換えようとしましたが、エラーはありませんが、それでも上書きされます。
あなたは、いくつかのコードが何を期待しませんどこをチェックする機会、そしてどのような状況で、メモリやレジスタの内容があるを持っているので、デバッガを使用することを学ぶために絶対にMUST。
あなたが8086エミュレータと互換性のアセンブラを検索するために、それはあまりにも怠惰な(私の頭の中で私は 3があなたの元の質問と徹底遅い(約10分)シミュレーションの読み取りを取った、デバッガなしで組み立てでプログラムする機会を持っていません私はあなたが文字列を上書きする理由を理解するまで、「唯一のCR」はソースから見つけるのが簡単ではないためです。そして私は何年ものx86アセンブリプログラミングをやって、メガバイトのASMソースコードを書きました。そして、このミスを発見するのはまだ難しかったです。私がデバッガを持っていて、それを実行すると、ユーザーの入力後にstring1
バッファの内容をチェックした直後に問題が発見されます。
また、別の例のデバッガの必要性を説明するために、私はASMプログラミングを学んだときにコンピュータを持っていなかったので、紙にコードを書く必要がありました。通常1週間に1回。通常、それはいくつかのバグが原因で墜落したが、私はマシン上で、それをデバッグするのに十分な時間を持っていなかったので、私は紙で自宅でバグを見つけなければならなかった(そしてインターネットがSOに尋ねるために戻って1985年の周りにありませんでした)。すべてのバグが修正されたバージョンの作業には3〜5週間かかりました。私がデバッガを使ってコンピュータを自由に使えたら、おそらく1時間ですべての修正を行うだろう。その後、再び、今私は(も、他のプログラミング言語で)ソースを読むことによってだけ多くのバグを参照してください、それは私の脳は、すべてのドット、昏睡や数に着目し、その紙の経験の後に行ってきました方法です...
私は8086を使用して、 movzxは動作しません。私は 'mov bl、[dx-1]'を試しましたが、 '(63)おそらく16進数のゼロ接頭辞はありません。または 'h'接尾辞なし。または間違ったアドレス指定。または未定義のVAR:[DX - 01H] ''私は、サブ[DX]、01、または '12月[DX]'を使用して、その周りに働いて試してみたが、それは同じエラーになります。 dxは間接アドレッシングでは受け入れられないので、bxに置き換えようとしましたが、エラーはありませんが、それでも上書きされます。私はdxで立ち往生しています。 – AnAn
@AnAnああ、リアルモードの喜び、私はそれらを完全に忘れてしまった。私は有効なリアルモードアドレッシングと8086命令で答えを数分で編集します(コードを検証するためにアセンブラをいくつか取得した後)。 BTW 'sub [dx]、1は' dx'からではなく、メモリの内容から1を引きます。角括弧 '[] 'は、"そこで値を操作するためのメモリへのアドレスとしての角括弧内の値の使用 "を意味します。答えの最後に – Ped7g
@AnAnは...基本的に新しい答えです...しかし、あなたは自分を試す難しくする必要がある、と私は、ランダムな推測や他の場所からのコードの一部のコピーペーストをしようとして意味するものではありません。それは高水準言語ではうまくいくかもしれませんが、アセンブリではあなたが書いたことを完全に理解しなければなりません。合理的な時間に正しいコードを「推測」する機会はありません。だからあなたの現在の問題から判断するあなたは、いくつかの書籍/チュートリアルを読む必要に数週間を過ごす(「スタック」に言及、LF + CR、間違って私の元のコードを修正することができないことは、 '[DX]'、デバッガを使用できないことに対処逆転しました)コードを使って実験してください。 – Ped7g