0

整数を読み込み、それに 1 を加えて結果を出力する必要がある練習問題に行き詰まっています。この質問について: linux nasm assembly print all numbers from zero to 100、ユーザー Gunner は dwtoa に言及しました。それは呼び出し可能な関数だと思います。では、この dwtoa 関数とは何ですか? そして、それが実際に呼び出し可能な関数である場合、どこで取得できますか (get とは、コードにどのように実装できるかということです)?

前もって感謝します。

4

1 に答える 1

3

ええと、それを書く必要があります... または誰かがすでに書いたものを借ります。後者の方が簡単ですが (C ライブラリにはこのような関数があり、asm から簡単に呼び出すことができます)、前者の方が「楽しい」です。(そういうのが好きなら、クロスワードパズルをする人もいます)

指導はdivとても遅いです。逆数と「逆乗算」を掛けることに基づいて、それを行うより良い方法があります。かなり複雑です。お待ちしておりdivます。:)

div ebx

番号、たとえば 1234 を に配置しeax、10 を配置した場合ebx、123 にeax4が配置されますedx(ebxは変更されません)。実際には、 ...edxの前に0 を入れたいと思います。div

xor edx, edx

div ebx

ご存じのように、文字「0」(または 10 進数の 48 または 30h) を追加することで、数値 4 を文字「4」に変換できます。これで、印刷できるものができました!しかし、まだ印刷する準備ができていません。桁を逆に取得しています。これに対処するにはいくつかの方法があります。push最も簡単なのは、スタック上に置くことだと思います。pop正しい順序でそれらをオフにします。もう 1 つの方法は、先に進んでバッファーに逆方向に配置し、最後に「文字列の反転」を行うことです。もう 1 つの方法は、バッファーの「最後」から始めて、先頭に向かって作業することです (インデックスをインクリメントするのではなく、各文字の後にバッファーにデクリメントします)。これは、桁がなくなったときにバッファの先頭に達していないことを意味する場合があります。これを有利に利用できます。列に印刷する場合は、右揃えの数値が見栄えがします。見栄えが良いと思われる場合は、先行ゼロ (数字の 0 ではなく文字「0」) で埋めることもできます (私はしません)。

いずれにせよ、「4」は安全に保管されています。何度もループしますdiv(edx最初にゼロにします!)。これで 12 インチeaxと 3インチになりましたedx。3で何かをして、divもう一度戻ってください。1インチeaxと2インチedx。繰り返しますが、 andeaxは 0 (edxは 1) です - その時点で完了です! div9と比較すると、最後の桁をスキップできます。9 より小さい場合は、代わりにeaxから最後の (最初に出力される) 桁を取得できます。毎回同じ方法で行う方が簡単です... aldl

; mov eax, the number
; mov edi, the buffer (at least resb 10, please)
; call dwtoa
; mov edx, eax ; count
; mov ecx, buffer
; print it

dwtoa:
    xor ecx, ecx ; for a counter
    mov ebx, 10
pushloop:
    xor edx, edx ; or mov edx, 0
    div ebx
    add edx, '0'
    push edx
    inc ecx ; count it
    test eax, eax ; or cmp eax, 0
    jnz pushloop
    mov eax, ecx ; we'll return the count in eax
poploop:
    pop edx
    mov [edi], dl
    inc edi
    loop poploop
    ret

それは私の頭のてっぺんから外れており(カットアンドペーストではありません)、エラーがある可能性があります。それはかなりずさんです-Cが保存したいレジスタを破棄します-Cが望むようにゼロで終わる文字列を返しません...しかし、私たちはCを使用していないので気にしません! :)

好みに合わせて改良するか、別の方法を試してみてください。

ユーザーが入力したテキストを数値に変換するには、"atoi" (または同じ命名規則を使用する "atodw") を使用する必要があります。同じ考えですが、文字から「0」を引き、「これまでの結果」に 10 を掛け、新しい数字を足します... 完了するまで。

;-------------------
; atoi - converts string to (unsigned!) integer
; expects: buffer in edx
; returns: number in eax
atoi:
    xor eax, eax        ; clear "result"
.top:
    movzx ecx, byte [edx]
    inc edx

    cmp ecx, byte 0
    jz .done
    cmp ecx, byte 10
    jz .done

    cmp ecx, byte '0'
    jb .invalid
    cmp ecx, byte '9'
    ja .invalid

    ; we have a valid character - multiply
    ; result-so-far by 10, subtract '0'
    ; from the character to convert it to
    ; a number, and add it to result.

    lea eax, [eax + eax * 4]
    lea eax, [eax * 2 + ecx - '0']

    jmp short .top
.invalid:
    stc
.done:
    ret
;--------------

それはカットアンドペーストなので、「うまくいく」はずです。それもまた、改善される可能性があります。「興味深い」方法を使用して、10 を掛け、数値に変換された新しい文字を追加します。この時点で、プログラムの「作業」は 次のadd eax, 1 ようになります。楽しむ!:)

于 2012-11-07T12:36:43.913 に答える