如何将表示有符号十六进制int的字符串转换为80x86中的signed int双字数?

时间:2013-04-16 21:07:20

标签: string assembly x86 hex ascii

所以我参加了汇编语言课程,我从书中坚持这个问题: 使用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

我正在尝试将ASCII字符串转换为十六进制的TestForHex标签。我环顾四周,读到我可以通过移动和遮蔽来完成我的目标,但我无法弄明白,我找不到任何例子。在这一点上,我确信它的东西非常小,我只是在看,但我被卡住了。

2 个答案:

答案 0 :(得分:2)

您的代码中存在一些错误。

首先,在 0 ... 9 字符串到整数转换代码中,您不应该像您应该那样进行ASCII到二进制转换,而是执行and ebx,0Fh,这是不正确。您需要从每个ASCII字符中减去'0'30h),如下所示:

mov bl,[esi]
sub bl,'0' ; sub bl,30h

然后,也在 0 ... 9 字符串到整数转换代码:

and    eax, ebx

如果数字只包含0 ... 9位数,and eax, ebx将始终为0。应该是:

or al,bl

然后,即使您不知道是否会有更多数字,您也会shl eax,4。这意味着该数字将比它应该大16倍。

然后,您为示例输入提供了空格,但是您的代码没有正确处理空格(20h),它结束读取'0'30h)以下任何值的输入,它似乎只接受前导空格(如果你不想在它们之间接受空格,请跳过它)。

因此,上面的整个代码块应该是:

WhileDigitD:
        cmp    byte ptr [esi], ' ' ; delete this if you don't want spaces in between.
        je     next_char           ; delete this if you don't want spaces in between.
        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

        sub    bl,'0'              ; sub bl,30h -> convert ASCII to binary.

shift_eax_by_4_and_add_bl:
        shl    eax,4               ; shift the current value 4 bits to left.
        or     al,bl               ; add the value of the current digit.

next_char:
        inc    esi
        jmp    WhileDigitD

我还添加了标签next_charshift_eax_by_4_and_add_blnext_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 - &gt; 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 -> convert ASCII to binary.
        jmp    shift_eax_by_4_and_add_bl

答案 1 :(得分: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

在这里,您利用了ASCII字符09具有连续ASCII码的事实,ASCII字符AF也是如此。