简体   繁体   English

在 MIPS 中使用 syscall 8 验证用户输入

[英]Verifying user input using syscall 8 in MIPS

I'm struggling to figure an efficient way to check if the user entered a valid input which is only numbers (0~9), using syscall 8我正在努力寻找一种有效的方法来检查用户是否输入了一个有效的输入,它只是数字 (0~9),使用 syscall 8

the input is 4 bytes long (1 word),输入长度为 4 个字节(1 个字),
and I need to check for each byte (char) if it's a number or not,我需要检查每个字节(字符)是否是数字,

I thought of trying to run through a loop and check if its ascii value is lower than 48 ('0' ascii decimel value),我想尝试运行一个循环并检查其 ascii 值是否低于 48('0' ascii 十进制值),
or higher than 57('9' ascii decimel value),或高于 57('9' ascii 十进制值),

Is this an efficient way of doing this?这是一种有效的方法吗?
and if so, what's the right way to implement such if statement in MIPS?如果是这样,在 MIPS 中实现这样的 if 语句的正确方法是什么?
for example例如

if (x < 48) or (x > 57) {...}

*Note: assume I do have a flag to know where to stop the loop *注意:假设我确实有一个标志来知道在哪里停止循环

*Edit: this is a segment of the code, to make it clearer: *编辑:这是一段代码,使其更清晰:

.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

Try this:尝试这个:

    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

The unsigned compare trick for range checks is good here, getting the job done with only sub/sltiu/beq, and giving you the ASCII->integer digit value as part of it .用于范围检查的无符号比较技巧在这里很好,只需使用 sub/sltiu/beq 即可完成工作,并为您提供 ASCII->整数数字值作为其中的一部分

x86 example . x86 示例 Like for checking for alphabetic characters, see What is the idea behind ^= 32, that converts lowercase letters to upper and vice versa?就像检查字母字符一样,请参阅^= 32 背后的想法是什么,将小写字母转换为大写字母,反之亦然?

Zero-extend or sign-extend a character (a byte) into a 32-bit register;将字符(一个字节)零扩展或符号扩展到 32 位寄存器中; either one works because the ASCII 0..9 digit range is signed positive, and this range check correctly excludes all other 32-bit numbers.任何一个都有效,因为 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:

Input too low means t0 -= '0' wraps to a large unsigned value.输入太低意味着t0 -= '0'换行到一个大的无符号值。 Input too high means it's (unsigned) above 9 after subtracting.输入太高意味着减去后它(无符号)大于9

If you want to keep around the original character value as well as its integer digit value (if it's a digit), pick different registers.如果您想保留原始字符值及其整数数字值(如果它是数字),请选择不同的寄存器。

MARS unfortunately doesn't support convenient ASCII character constants as part of numeric expressions, so it can't assemble addiu $t0, $t0, -'0' to subtract '0' .不幸的是,MARS 不支持方便的 ASCII 字符常量作为数字表达式的一部分,因此它无法组合addiu $t0, $t0, -'0'来减去'0'

You can write sltiu / beqz as a bgeu $t0, 10, non_digit pseudo-instruction.你可以写sltiu / beqz作为bgeu $t0, 10, non_digit伪指令。

You could write bgtu $t0, 9, non_digit , but don't because MARS assembles that to 3 machine instructions (including addi to materialize 9 in a register + sltu between two regs), instead of 2. You can't save anything by using a register holding 9 or 10 setup before a loop, either: MIPS branch conditions only compare against zero, except for eq / ne.你可以写bgtu $t0, 9, non_digit ,但不要因为火星组装,为3个机器指令(包括addi兑现9的寄存器和sltu两个REG之间),而不是2.您可以通过救不了任何东西在循环之前使用保存910设置的寄存器,或者: MIPS 分支条件仅与零比较,eq / ne 除外。 blt $t1, $t9, non_digit would be a pseudo-instruction, too. blt $t1, $t9, non_digit也是伪指令。

Branching only once is of course very good on a real MIPS with branch-delay slots.在具有分支延迟槽的真实 MIPS 上,仅分支一次当然非常好。


You can of course use this as the loop condition for looping until you encounter a non-digit.您当然可以将其用作循环的循环条件,直到遇到非数字为止。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM