我很难找到一种有效的方法来检查用户是否输入了一个只有数字(0~9)的有效输入,使用系统调用8
输入长度为4个字节(1个字),
如果它是一个数字,我需要检查每个字节(字符),
我想过尝试运行循环并检查其ascii值是否低于48('0'ascii decimel value),
或高于57('9'ascii decimel值),
这是一种有效的方式吗?
如果是这样,在MIPS中实现if语句的正确方法是什么?
例如
if (x < 48) or (x > 57) {...}
*注意:假设我有一个标志知道在哪里停止循环
*编辑:这是代码的一部分,以使其更清晰:
.data
number:
.word w1
.text
.globl main
main:
la $a0, number # read the number input from user
li $a1, 6 # buffer set to max of 4 bytes (32 bits),
# assuming the input is no more than the length of a word,
# + 2 reserved bytes
li $v0, 8
syscall
答案 0 :(得分:1)
试试这个:
lbu $t0, x # read next byte
sltiu $t1, $t0, 48 # t1 = (x < 48) ? 1 : 0
bnez $t1, fail
sltiu $t1, $t0, 58 # t1 = (x < 58) ? 1 : 0
beqz $t1, fail
# we now know that 48 <= $t1 <= 57
. . .
. . .
fail: # input byte was not a digit if we get to here
答案 1 :(得分:0)
在这里进行范围检查的无符号比较技巧非常有用,只需使用sub / sltiu / beq即可完成工作,并为其提供ASCII->整数数字值。 >
x86 example。就像检查字母字符一样,请参见What is the idea behind ^= 32, that converts lowercase letters to upper and vice versa?
将一个字符(一个字节)零扩展或符号扩展到32位寄存器中;由于ASCII 0..9的数字范围为正号,所以该方法均有效,并且此范围检查正确排除了所有其他32位数字。
# lbu $t0, x # for example
# ASCII character in $t0
addiu $t0, $t0, -0x30 # subtract '0' : range shift from '0'..'9' to 0..9
sltiu $t1, $t0, 10 # t1 = c < 10 unsigned
beqz $t1, non_digit # jump if c>=10
# fall through: it was a digit, 0..9 value in $t0
...
non_digit:
输入值太低意味着t0 -= '0'
包装到一个较大的无符号值。输入太高意味着减去后它在9
上方(无符号)。
如果要保留原始字符值及其整数数字值(如果是数字),请选择其他寄存器。
不幸的是,MARS不支持将方便的ASCII字符常量用作数字表达式的一部分,因此它无法汇编addiu $t0, $t0, -'0'
减去'0'
。
您可以将sltiu
/ beqz
作为bgeu $t0, 10, non_digit
伪指令编写。
您可以编写bgtu $t0, 9, non_digit
,但不能这样做,因为MARS会将其汇编为3条机器指令(包括addi
以在两个寄存器之间的寄存器+ 9
中实现sltu
),而不是2。您无法通过在循环前使用保存9
或10
设置的寄存器来保存任何内容,或者:MIPS分支条件仅与零进行比较,但eq / ne除外。 blt $t1, $t9, non_digit
也将是伪指令。
在具有分支延迟插槽的真正MIPS上,仅分支一次当然非常好。
您当然可以将其用作循环条件,直到遇到非数字为止。