0

だから私はアセンブリ言語コースを受講していますが、本からこの問題に固執しています: Windows 32コンソールを使用して(io.h使用する必要があるため)、ユーザーが入力した有効な16進値を取得してから表示することになっていますレジスタ内の実際の 16 進数値EAX。したがって、ユーザーが「AB CD E2 18」と入力した場合、手順の後にEAX値が保持されますABCDE218。私が立ち往生している部分はA-F値です。たとえば、使用Aする場合、読み取るビットを取得できますが00000010、それを16進値に変更する方法がわかりませんA。これが私がこれまでに持っているものです:

.586
.MODEL FLAT
.CODE

hexToInt    PROC
        push   ebp                 ; save base pointer
        mov    ebp, esp            ; establish stack frame
        sub    esp, 4              ; local space for sign
        push   ebx                 ; Save registers
        push   edx
        push   esi
        pushfd                     ; save flags

        mov    esi,[ebp+8]         ; get parameter (source addr)

WhileBlankD:
        cmp    BYTE PTR [esi],' '  ; space?
        jne    EndWhileBlankD      ; exit if not
        inc    esi                 ; increment character pointer
        jmp    WhileBlankD         ; and try again
EndWhileBlankD:

        mov    eax,1               ; default sign multiplier
IfPlusD:cmp    BYTE PTR [esi],'+'  ; leading + ?
        je     SkipSignD           ; if so, skip over
IfMinusD:
        cmp    BYTE PTR [esi],'-'  ; leading - ?
        jne    EndIfSignD          ; if not, save default +
        mov    eax,-1              ; -1 for minus sign
SkipSignD:
        inc    esi                 ; move past sign
EndIfSignD:

        mov    [ebp-4],eax         ; save sign multiplier
        mov    eax,0               ; number being accumulated

WhileDigitD:
        cmp    BYTE PTR [esi],'0'  ; compare next character to '0'
        jb     EndWhileDigitD      ; not a digit if smaller than '0'
        cmp    BYTE PTR [esi],'9'  ; compare to '9'
        ja     TestForHexD      
        mov    bl,[esi]            ; ASCII character to BL
        and    ebx,0000000Fh       ; convert to single-digit integer
        and    eax, ebx
        shl    eax, 4
        inc    esi
        jmp    WhileDigitD
TestForHexD:
        cmp    BYTE PTR [esi], 'F'
        ja     EndWhileDigitD
        mov    bl, [esi]
        sub    bl, 31h
        and    ebx, 000000FFh
        or     al, bl
        shl    eax, 4
        inc    esi                 ; increment character pointer
        jmp    WhileDigitD         ; go try next character
EndWhileDigitD:

; if value is < 80000000h, multiply by sign
        cmp    eax,80000000h       ; 80000000h?
        jnb    endIfMaxD           ; skip if not
        imul   DWORD PTR [ebp-4]   ; make signed number
endIfMaxD:

        popfd                      ; restore flags
        pop    esi                 ; restore registers
        pop    edx
        pop    ebx
        mov    esp, ebp            ; delete local variable space
        pop    ebp 
        ret                        ; exit
hexToInt    ENDP

        END

ラベルは、TestForHexASCII 文字列を 16 進数に変換しようとしている場所です。私は周りを見回して、シフトとマスキングによって目標を達成できると読みましたが、それを理解できず、例も見つかりません。この時点で、私はそれが本当に小さなものであり、見過ごしているだけだと確信していますが、行き詰まっています。

4

2 に答える 2

2

コードにいくつかのバグがあります。

まず、0 ... 9文字列から整数への変換コードでは、本来行うべき ASCII からバイナリへの変換を行っていませんが、代わりに を行っていますがand ebx,0Fh、これは正しくありません。次のように、各 ASCII 文字から'0'( )を減算する必要があります。30h

mov bl,[esi]
サブ bl、'0' ; サブ bl,30h

次に、同じく0 ... 9文字列から整数への変換コード:

そしてeax、ebx

数値が 0 ~ 9 桁のみで構成されている場合、and eax, ebx常に 0 が生成されます。次のようにする必要があります。

またはal、bl

次に、shl eax,4桁数が増えるかどうかわからなくても、 を実行します。これは、数値が本来の 16 倍になることを意味します。

次に、例の入力にスペースを指定しますが、コードはスペース ( 20h) を適切に処理せず、以下の値の入力の読み取りを終了します'0'( 30h)。先頭のスペースのみを受け入れるようです (受け入れたくない場合はこれをスキップしてください)。間のスペース)。

したがって、上記のコード ブロック全体は次のようになります。

WhileDigitD:
        cmp バイト ptr [esi], ' ' ; 間にスペースを入れたくない場合は、これを削除してください。
        je next_char ; 間にスペースを入れたくない場合は、これを削除してください。
        cmp BYTE PTR [esi],'0' ; 次の文字を「0」と比較
        jb EndWhileDigitD ; 「0」より小さい場合は数字ではありません
        cmp BYTE PTR [esi],'9' ; '9' と比較
        ja TestForHexD      
        mov bl,[esi] ; ASCII 文字から BL へ

        サブ bl、'0' ; sub bl,30h -> ASCII をバイナリに変換します。

shift_eax_by_4_and_add_bl:
        shl eax,4 ; 現在の値を 4 ビット左にシフトします。
        またはal、bl; 現在の桁の値を追加します。

次の文字:
        inc esi
        jmp WhileDigitD

ラベルnext_charとも追加しましshift_eax_by_4_and_add_blた。の理由はnext_char明らかで、shift_eax_by_4_and_add_bl0...9 および A...F コード ブロックの重複コードを最小限に抑えるためです。以下を参照してください。

16 進数の A...F 桁がA ... F の範囲内にあることを確認せず、 F以下であることのみを確認します。そうでなければ、 と同じバグがありshl eax,4ます。また、通常は重複コードを避ける必要があるため、shift_eax_by_4_and_add_blラベルを追加して重複コードを最小限に抑えました。

だから私はそれがあるべきだと思う:

編集:修正sub bl,31h-> sub bl,('A'-0Ah).

TestForHexD:
        cmp BYTE PTR [esi], 'A'
        jb EndWhileDigitD
        cmp BYTE PTR [esi], 'F'
        ja EndWhileDigitD
        mov bl,[esi]
        サブ bl,('A'-0Ah) ; sub bl,55 -> ASCII をバイナリに変換します。
        jmp shift_eax_by_4_and_add_bl
于 2013-04-16T22:09:13.273 に答える
1

16 進数を表す文字 (簡単にするために、たとえば大文字) をその数字の値に変換する必要がある場合は、次のようにする必要があります。

IF char >= 'A'
  value = char - 'A' + 10
ELSE
  value = char - '0'
ENDIF

逆を行う必要がある場合は、逆を行います。

IF value >= 10
  char = value - 10 + 'A'
ELSE
  char = value + '0'
ENDIF

ここでは、 から までの ASCII 文字が連続した ASCII コードを持ち、 から までの ASCII 文字も同様で0あるという事実を利用します。9AF

于 2013-04-16T22:08:48.607 に答える