0

所以我正在上一门汇编语言课程,我被书中的这个问题困住了:使用 windows 32 控制台(所以我可以io.h使用),我应该采用用户输入的有效十六进制值,然后显示寄存器中的实际十六进制值EAX。所以如果用户输入“AB CD E2 18”,那么程序之后EAX会保存这个值:ABCDE218。我坚持的部分是A-F值。例如,如果我使用A,我可以获得要读取的位00000010,但我不知道如何将其更改为十六进制值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

TestForHex标签是我试图将 ASCII 字符串转换为十六进制的地方。我环顾四周,读到我可以通过移位和屏蔽来实现我的目标,但我无法弄清楚,也找不到任何例子。在这一点上,我确信它确实很小,我只是在看,但我被卡住了。

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

所以,上面的整个代码块应该是:

而数字D:
        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 ; 添加当前数字的值。

下一个字符:
        公司
        jmp WhileDigitD

我还添加了标签next_charshift_eax_by_4_and_add_bl. 原因next_char应该很明显,shift_eax_by_4_and_add_bl是为了尽量减少 0...9 和 A...F 代码块的重复代码,见下文。

您不会检查十六进制 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]
        sub bl,('A'-0Ah) ; sub bl,55 -> 将 ASCII 转换为二进制。
        jmp shift_eax_by_4_and_add_bl
于 2013-04-16T22:09:13.273 回答
1

如果您需要将代表十六进制数字的字符(为简单起见,例如大写)转换为该数字的值,则需要执行以下操作:

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

如果你需要做相反的事情,你做相反的事情:

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

0在这里,您利用了 ASCII 字符通过9具有连续 ASCII 码的事实, ASCII 字符A通过F.

于 2013-04-16T22:08:48.607 回答