我正在编写一个程序,询问用户他们的温度,然后获取该输入并转换和输出所有四个温度。我需要帮助让我的用户输入读入,以便它可以在我的分支中工作,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(和任何其他通用 CPU)没有“比较字符串”指令,字符串不是 CPU 的本机类型,指令仅处理本机类型,如字和字节。
“字符串”是一定数量(在某处定义,或在数据末尾使用终止符)的连续字符。什么是“一个字符”取决于使用的编码,在您的情况下(MARS 模拟器和 asm 编程的简单实践),您可以坚持使用旧的 ASCII 编码,其中单个字符恰好是一个单字节。(JFYI:使用现代软件,您将主要使用 UTF8 编码,就像这个网页所做的那样,其中单个字符可以有不同数量的字节,这取决于您编码的字形,这使得通过 UTF8 编码的字符串编程任何字符串算法变得更加有趣比你当前的任务。通常太有趣了。)
现在,由于 CPU 寄存器是“字”大小,这意味着它们是 32 位“宽”,即它们一次最多可以容纳 4 个 ASCII 字符(4 个字节),因此使用寄存器来存储整个字符串将只允许非常笑。海峡 和_没有别的。您可以这样做,但这是不切实际的(除了beq
可以工作,因为您可以将单词 value 0x30303030
="0000"
与0x31313131
="1111"
与进行比较beq
)。
因此,大多数时候在 MIPS 初学者汇编中编程时,“字符串”遵循以下模式:某些寄存器包含指向字符串第一个字母(字符串的第一个字节)的内存地址,并且字符串的最后一个“字符”不是任何字母,但值为零,即所谓的“空终止符”。
当您想要比较字符串时,您可以创建循环,该循环以两个指针开始(指向两个字符串 = 指向两个首字母)。将两个地址中的字节加载到某个临时寄存器中(即加载两者的第一个字母),将其与字符串进行比较,如果它们不同,则字符串不同。如果相等,则检查是否为零(两个字符串都结束 = 它们相等)。如果不为零,则将两个地址都加一,以便它们指向下一个字母,并循环到开头。
但是在您的情况下,用户只能输入单个字母,而您只想比较单个字母,因此编写整个循环是一种繁重的工作,您只需加载该单个字母并进行比较即可。
因此,从顶部阅读您的来源,这些行将得到我的评论:
#li $a1, 2
为什么被注释掉?您应该使用它来限制系统调用(我认为不设置任何内容,默认值可能为零,因此不会发生任何输入)。此外,您可能对syscall(v0=12) “读取字符”而不是“读取字符串”感兴趣,但我不确定在 MARS 中如何向用户呈现它(用户体验相关),但让我们坚持使用服务 v0= 8 个“读取字符串”和 2 字节长的缓冲区。
现在syscall
返回后(用户确实输入了字母“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
vs102
肯定不相等,因此beq
永远不会跳转到 label 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 = $1, $zero = $0
beq $at, $t2, fahrenheit
为你节省一些打字,这在编程中是好的,只要它在阅读时有意义(一旦你开始为了简短的写作而缩短源代码,你就做错了,在编程中编写源代码被读取,与读取成本相比,写入成本可以忽略不计)。在这种情况下,beq $t2, 'f', label
对我来说看起来很有可读性,所以我更喜欢这样。
这应该足以回答您的两个问题,明确的问题(如何在循环中逐个字符地比较字符串 =)和隐含的问题(如何将用户的单个字母与 'f' 进行比较)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句