1

我正在努力寻找一种有效的方法来检查用户是否使用系统调用 8 输入了只有数字(0~9)的有效输入

输入是 4 个字节长(1 个字),
我需要检查每个字节(char)是否是数字,

我想过尝试运行一个循环并检查它的 ascii 值是否低于 48('0' ascii 十进制值),
或高于 57('9' ascii 十进制值),

这是一种有效的方法吗?
如果是这样,在 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
4

2 回答 2

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
于 2012-11-24T22:14:55.233 回答
0

用于范围检查的无符号比较技巧在这里很好,只使用 sub/sltiu/beq 完成工作,并为您提供 ASCII->integer 数字值作为其中的一部分

x86 示例。就像检查字母字符一样,请参阅^= 32 背后的想法是什么,它将小写字母转换为大写字母,反之亦然?

零扩展或符号扩展一个字符(一个字节)到一个 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/写beqzbgeu $t0, 10, non_digit伪指令。

您可以编写bgtu $t0, 9, non_digit,但不要编写,因为 MARS 将其组装为 3 个机器指令(包括addi9寄存器中实现 +sltu两个 regs 之间),而不是 2。您无法通过在循环之前使用寄存器保持9或设置来保存任何内容,10两者之一:MIPS 分支条件仅与零比较,eq / ne 除外。 blt $t1, $t9, non_digit也将是一个伪指令。

在具有分支延迟槽的真实 MIPS 上,只分支一次当然是非常好的。


您当然可以将其用作循环条件,直到遇到非数字为止。

于 2020-07-31T21:28:22.023 回答