您好,这是 x86 处理器的汇编语言,使用 Visual Studio 2019 进行编译。 我仅使用 Irvine32 库中的指令进行基于标志的跳转。 我要求用户输入一个字符来决定该字符是否是大写/小写字母,或者用户是否输入了数字。如果用户输入了除这两个命令之外的任何其他内容,则它应该通过跳转命令并仅输出错误消息并退出。我的问题是小写字母和数字跳转到小写输出。这是代码
.data
digit BYTE "Number",0ah,0dh,0
upper BYTE "Upper case",0ah,0dh,0
lower BYTE "Lower case",0ah,0dh,0
prompt BYTE "Enter input from keyboard",0ah,0dh,0
error BYTE "Error. Neither (0/A)",0ah,0dh,0
.code
main PROC
mov edx, OFFSET prompt
mov eax, 0
call writeString
call readChar
call isLower
cmp eax, 0
jz ISUP
JNZ Lowrr
mov edx, 0
call isDigit
test eax, 0
JZ Number
mov edx, offset error
call writeString
JMP EXITOUT
Lowrr:
mov edx, OFFSET lower
call writeString
jmp EXITOUT
ISUP:
MOV EDX, OFFSET upper
call writeString
JMP EXITOUT
Number:
MOV EDX, OFFSET digit
call writeString
JMP EXITOUT
EXITOUT:
exit
main ENDP
isLower PROC
cmp al, "A"
JnZ LOWERTRUE
jnC LOWERFALSE
cmp al, "Z"
JnZ LOWERTRUE
JC LOWERFALSE
LOWERTRUE:
mov eax, 1
ret
LOWERFALSE:
mov eax, 0
ret
isLower ENDP
isDigit PROC
cmp al, "0"
JZ DigitTRUE
jC DigitFALSE
cmp al, "9"
JZ DigitTRUE
JnC DigitFALSE
DigitTRUE:
mov eax, 1
ret
DigitFALSE:
mov eax, 0
ret
isDigit ENDP
END main
call isLower cmp eax, 0 jz ISUP JNZ Lowrr mov edx, 0 call isDigit test eax, 0 JZ Number
jz
和jnz
涵盖了cmp eax, 0
指令的所有可能结果。因此,程序甚至永远不会调用 isDigit。也许这样也好,因为原本应该出现在 AL
寄存器中的字符已经不存在了! isLower 在 EAX
寄存器中返回结果,从而销毁该字符。 (AL
是 EAX
的一部分)。
当你用零测试一个数字时,结果将始终为零。因此代码
test eax, 0
jz Number
总是会跳转!
当isLower返回FALSE时,那么你不能仅仅断定该字符是大写的。你只能断定该字符不是小写,除此之外别无其他。这段代码应该是:
call isLower
cmp eax, 1
je Lowrr
cmp al, "0" JZ DigitTRUE jC DigitFALSE cmp al, "9" JZ DigitTRUE JnC DigitFALSE DigitTRUE: mov eax, 1 ret DigitFALSE: mov eax, 0 ret
就其本身而言,与“0”比较后的
jz DigitTRUE
是正确的。与“9”比较后,jz DigitTRUE
也一样。然而,这些都不是富有成效的指示。jc DigitFALSE
没问题,但与“9”比较后的 jnc DigitFALSE
遗憾的是不会将“9”识别为数字(相等清除 CF)!这就是为什么你写了那些多余的jz DigitTRUE
,不是吗。
cmp al, "A" JnZ LOWERTRUE jnC LOWERFALSE cmp al, "Z" JnZ LOWERTRUE JC LOWERFALSE LOWERTRUE: mov eax, 1 ret LOWERFALSE: mov eax, 0 ret
在旨在验证小写的代码中与大写字符进行比较很奇怪。而
cmp al, "A"
JnZ LOWERTRUE
这对意味着实际上除了一个字符“A”之外的所有内容都会自动视为小写。进一步的分析就变得毫无意义。考虑数字、大写字母和小写字母在 ASCII 表中的位置:
48 57 65 90 97 122
0 ... 9 A ... Z a ... z
这些是我的 IsDigit、IsUpper 和 IsLower 的(较短)代码。它们返回
CF
清除为 TRUE 和 CF
设置为 FALSE。这样,AL
寄存器中的字符就可以保持完整以供后续验证:
; IN (al) OUT (CF)
IsDigit PROC
cmp al, "0" ; Lower bound
jb Digit_
cmp al, "9" + 1 ; Upper bound plus 1
cmc
Digit_:
ret
IsDigit ENDP
; IN (al) OUT (CF)
IsUpper PROC
cmp al, "A" ; Lower bound
jb Upper_
cmp al, "Z" + 1 ; Upper bound plus 1
cmc
Upper_:
ret
IsUpper ENDP
; IN (al) OUT (CF)
IsLower PROC
cmp al, "a" ; Lower bound
jb Lower_
cmp al, "z" + 1 ; Upper bound plus 1
cmc
Lower_:
ret
IsLower ENDP
将其绑定在一起变得极其简单:
mov edx, OFFSET digit
call IsDigit ; -> CF
jnc WriteIt
mov edx, OFFSET upper
call IsUpper ; -> CF
jnc WriteIt
mov edx, OFFSET lower
call IsLower ; -> CF
jnc WriteIt
mov edx, OFFSET error
WriteIt:
call writeString