所以我参加了汇编语言课程,我从书中坚持这个问题:
使用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
标签。我环顾四周,读到我可以通过移动和遮蔽来完成我的目标,但我无法弄明白,我找不到任何例子。在这一点上,我确信它的东西非常小,我只是在看,但我被卡住了。
答案 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_char
和shift_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
- &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字符0
到9
具有连续ASCII码的事实,ASCII字符A
到F
也是如此。