如何比较存储的字符串和输入的字符串-MIPS
How to compare stored strings with inputted strings-MIPS
我正在编写一个程序,询问用户他们有哪个温度,然后获取该输入并转换和输出所有四个温度。我需要帮助让我的用户读入输入,以便它可以在我的分支 beq 中工作。我无法让它将输入 'f' 识别为等于存储的版本。
.data
temptype: .asciiz "Enter temperature type i.e. f, c, k, r: "
tempdegree: .asciiz "\n Enter degrees: "
space: .space 2
tempx: .asciiz "Your temperature in celsius is: "
tempc: .asciiz "\nYour temperature in celsius is: "
tempf: .asciiz "\nYour temperature in fahrenheit is: "
tempk: .asciiz "\nYour temperature in kelvin is: "
tempr: .asciiz "\nYour temperature in rankine is: :"
kr: .float 459.67
.globl main
.text
main:
li $v0, 4
la $a0, temptype
syscall
li $v0, 8
la $a0, space
#li $a1, 2
move $t0, $a0
syscall
li $t1, 102
#li $t1, 99
#li $t1, 107
#li $t1, 114
syscall
beq $t0, $t1, fahrenheit
#beq $t0, $t1, celsius
#beq $t0, $t1, kelvin
#beq $t0, $t1, rankine
syscall
li $v0,10
syscall
fahrenheit:
li $v0, 4
la $a0, tempdegree
syscall
li $v0, 5
syscall
move $t0, $v0
li $v0, 4
la $a0, tempf
syscall
move $a0, $t0
li $v0, 1
syscall
MIPS CPU(和任何其他常见的 none)没有 "compare strings" 指令,字符串不是 CPU 的原生类型,指令只处理本机类型,如单词和字节。
"String" 是一定数量(在某处定义,或在数据末尾使用终止符)的连续字符。什么是 "one character" 取决于使用的编码,在您的情况下(MARS 模拟器和 asm 编程的简单实践)您可以坚持使用旧的 ASCII 编码,其中单个字符正好是一个字节。 (仅供参考:使用现代软件,您将主要使用 UTF8 编码,就像这个网页一样,其中单个字符可以有不同的字节数,具体取决于您编码的字形,这使得通过 UTF8 编码的字符串编写任何字符串算法更有趣比你当前的任务。通常太有趣了。)
现在 CPU 寄存器的大小为 "word",这意味着它们是 32 位 "wide",即它们一次最多可以容纳 4 个 ASCII 字符(4 个字节) ,所以使用寄存器来存储整个字符串只允许非常 sho。海峡而且_没有别的。你可以这样做,但它不实用(除了 beq
会起作用,因为你可以将单词值 0x30303030
= "0000"
与 0x31313131
= "1111"
与beq
).
因此,大多数时候在 MIPS 初学者汇编程序中编程 "strings" 遵循以下模式:一些寄存器包含指向字符串第一个字母(字符串的第一个字节)的内存地址,最后一个 "character" 的字符串不是任何字母,而是零值,即所谓的 "null terminator".
当你想要比较字符串时,你创建了循环,它以两个指针开始(指向两个字符串 = 指向前两个字母)。将两个地址的字节加载到某个临时寄存器(即加载两者的第一个字母),比较它,如果它们不同,则字符串不同。如果相等,检查零(两个字符串结束 = 它们相等)。如果不为零,将两个地址前移一个,这样它们将指向下一个字母,并循环到开头。
但是在你的情况下,用户只能输入单个字母,而你只想比较单个字母,因此编写整个循环有点费力,你可以只加载那个字母并进行比较。
所以从顶部阅读你的来源,这些行将得到我的评论:
#li $a1, 2
为什么被注释掉了?您应该使用它来限制系统调用(我认为不设置任何默认值可能为零,因此不会发生输入)。此外,您可能对 syscall(v0=12) "read character" 而不是 "read string" 感兴趣,但我不确定它是如何在 MARS 中呈现给用户的(与用户体验相关),但让我们坚持使用服务 v0 =8 "read string" 和 2 字节长缓冲区。
现在在 syscall
returns(用户确实输入了字母 "f")之后,地址 space
的内存将包含系统调用设置的两个字节:102、0 .
li $t1, 102
看起来很熟悉,但对于其他程序员来说很难阅读,使用 MARS 汇编程序您也可以使用这种方式来编写该数字:li $t1, 'f'
- 简单的撇号告诉汇编程序您想要单个 ASCII 字符的值('ab'
在 MARS 中是错误的,只能使用单个字符,其他一些汇编程序可能会将 'ab' 翻译为两个字节值)
下一个未注释的指令是:
syscall
您在这里问的是哪个 MARS 服务?您没有在 v0
中设置任何值,也不需要任何服务,因此如果您要在调试器中单步执行代码,这对您来说应该毫无意义,如果您推断每条指令会发生什么.
然后是beq $t0, $t1, fahrenheit
。
此时 t1
等于 'f'
,并且 t0
等于该缓冲区第一个字节的地址,在期间也别名为 space
符号编译,它等于某个 32 位值,可能类似于 0x100000c
。值 0x100000c
与 102
肯定不相等,因此 beq
永远不会跳转到标签 fahrenheit
.
要比较缓冲区中的第一个字母,首先从内存中获取它的值,如 lb $t2, ($t0)
,从 t0
中的地址加载字节值(高级信息:lb
将签名-将8位值扩展为32位值。ASCII的基本可打印字符都小于128,因此不需要处理负值,但如果字母'f'编码为140,则使用lb
将该值加载到 t2
会产生 32 位值 -116
,而不是 140
...正如我所写,基本 ASCII 只有 7 位,所以只有正值,这有效正如预期的那样,102 被加载为 102)。
然后你可以用 beq $t2, $t1, fahrenheit
取得更大的成功,因为现在它会将 ASCII 字符与 ASCII 字符进行比较。
您还可以使用 MARS MIPS 汇编伪指令beq $t2, 'f', fahrenheit
。 MARS 会将其编译为两条本机指令:
addi $at, $zero, 102 # 102 = 'f', $at = , $zero = [=13=]
beq $at, $t2, fahrenheit
省去一些打字,这在编程中很好,只要在阅读时有意义(一旦你为了简短的写作而开始缩短你的源代码,你就错了,在编程中源代码是为了被阅读而编写的,与阅读成本相比,编写成本可以忽略不计)。在这种情况下 beq $t2, 'f', label
对我来说看起来很可读,所以我更喜欢那样。
这应该足以回答您的两个问题,显式问题(如何在循环中逐字符比较字符串 =)和隐式问题(如何比较用户的单个字母与 'f').
我正在编写一个程序,询问用户他们有哪个温度,然后获取该输入并转换和输出所有四个温度。我需要帮助让我的用户读入输入,以便它可以在我的分支 beq 中工作。我无法让它将输入 'f' 识别为等于存储的版本。
.data
temptype: .asciiz "Enter temperature type i.e. f, c, k, r: "
tempdegree: .asciiz "\n Enter degrees: "
space: .space 2
tempx: .asciiz "Your temperature in celsius is: "
tempc: .asciiz "\nYour temperature in celsius is: "
tempf: .asciiz "\nYour temperature in fahrenheit is: "
tempk: .asciiz "\nYour temperature in kelvin is: "
tempr: .asciiz "\nYour temperature in rankine is: :"
kr: .float 459.67
.globl main
.text
main:
li $v0, 4
la $a0, temptype
syscall
li $v0, 8
la $a0, space
#li $a1, 2
move $t0, $a0
syscall
li $t1, 102
#li $t1, 99
#li $t1, 107
#li $t1, 114
syscall
beq $t0, $t1, fahrenheit
#beq $t0, $t1, celsius
#beq $t0, $t1, kelvin
#beq $t0, $t1, rankine
syscall
li $v0,10
syscall
fahrenheit:
li $v0, 4
la $a0, tempdegree
syscall
li $v0, 5
syscall
move $t0, $v0
li $v0, 4
la $a0, tempf
syscall
move $a0, $t0
li $v0, 1
syscall
MIPS CPU(和任何其他常见的 none)没有 "compare strings" 指令,字符串不是 CPU 的原生类型,指令只处理本机类型,如单词和字节。
"String" 是一定数量(在某处定义,或在数据末尾使用终止符)的连续字符。什么是 "one character" 取决于使用的编码,在您的情况下(MARS 模拟器和 asm 编程的简单实践)您可以坚持使用旧的 ASCII 编码,其中单个字符正好是一个字节。 (仅供参考:使用现代软件,您将主要使用 UTF8 编码,就像这个网页一样,其中单个字符可以有不同的字节数,具体取决于您编码的字形,这使得通过 UTF8 编码的字符串编写任何字符串算法更有趣比你当前的任务。通常太有趣了。)
现在 CPU 寄存器的大小为 "word",这意味着它们是 32 位 "wide",即它们一次最多可以容纳 4 个 ASCII 字符(4 个字节) ,所以使用寄存器来存储整个字符串只允许非常 sho。海峡而且_没有别的。你可以这样做,但它不实用(除了 beq
会起作用,因为你可以将单词值 0x30303030
= "0000"
与 0x31313131
= "1111"
与beq
).
因此,大多数时候在 MIPS 初学者汇编程序中编程 "strings" 遵循以下模式:一些寄存器包含指向字符串第一个字母(字符串的第一个字节)的内存地址,最后一个 "character" 的字符串不是任何字母,而是零值,即所谓的 "null terminator".
当你想要比较字符串时,你创建了循环,它以两个指针开始(指向两个字符串 = 指向前两个字母)。将两个地址的字节加载到某个临时寄存器(即加载两者的第一个字母),比较它,如果它们不同,则字符串不同。如果相等,检查零(两个字符串结束 = 它们相等)。如果不为零,将两个地址前移一个,这样它们将指向下一个字母,并循环到开头。
但是在你的情况下,用户只能输入单个字母,而你只想比较单个字母,因此编写整个循环有点费力,你可以只加载那个字母并进行比较。
所以从顶部阅读你的来源,这些行将得到我的评论:
#li $a1, 2
为什么被注释掉了?您应该使用它来限制系统调用(我认为不设置任何默认值可能为零,因此不会发生输入)。此外,您可能对 syscall(v0=12) "read character" 而不是 "read string" 感兴趣,但我不确定它是如何在 MARS 中呈现给用户的(与用户体验相关),但让我们坚持使用服务 v0 =8 "read string" 和 2 字节长缓冲区。
现在在 syscall
returns(用户确实输入了字母 "f")之后,地址 space
的内存将包含系统调用设置的两个字节:102、0 .
li $t1, 102
看起来很熟悉,但对于其他程序员来说很难阅读,使用 MARS 汇编程序您也可以使用这种方式来编写该数字:li $t1, 'f'
- 简单的撇号告诉汇编程序您想要单个 ASCII 字符的值('ab'
在 MARS 中是错误的,只能使用单个字符,其他一些汇编程序可能会将 'ab' 翻译为两个字节值)
下一个未注释的指令是:
syscall
您在这里问的是哪个 MARS 服务?您没有在 v0
中设置任何值,也不需要任何服务,因此如果您要在调试器中单步执行代码,这对您来说应该毫无意义,如果您推断每条指令会发生什么.
然后是beq $t0, $t1, fahrenheit
。
此时 t1
等于 'f'
,并且 t0
等于该缓冲区第一个字节的地址,在期间也别名为 space
符号编译,它等于某个 32 位值,可能类似于 0x100000c
。值 0x100000c
与 102
肯定不相等,因此 beq
永远不会跳转到标签 fahrenheit
.
要比较缓冲区中的第一个字母,首先从内存中获取它的值,如 lb $t2, ($t0)
,从 t0
中的地址加载字节值(高级信息:lb
将签名-将8位值扩展为32位值。ASCII的基本可打印字符都小于128,因此不需要处理负值,但如果字母'f'编码为140,则使用lb
将该值加载到 t2
会产生 32 位值 -116
,而不是 140
...正如我所写,基本 ASCII 只有 7 位,所以只有正值,这有效正如预期的那样,102 被加载为 102)。
然后你可以用 beq $t2, $t1, fahrenheit
取得更大的成功,因为现在它会将 ASCII 字符与 ASCII 字符进行比较。
您还可以使用 MARS MIPS 汇编伪指令beq $t2, 'f', fahrenheit
。 MARS 会将其编译为两条本机指令:
addi $at, $zero, 102 # 102 = 'f', $at = , $zero = [=13=]
beq $at, $t2, fahrenheit
省去一些打字,这在编程中很好,只要在阅读时有意义(一旦你为了简短的写作而开始缩短你的源代码,你就错了,在编程中源代码是为了被阅读而编写的,与阅读成本相比,编写成本可以忽略不计)。在这种情况下 beq $t2, 'f', label
对我来说看起来很可读,所以我更喜欢那样。
这应该足以回答您的两个问题,显式问题(如何在循环中逐字符比较字符串 =)和隐式问题(如何比较用户的单个字母与 'f').