我正在编写一个程序,询问用户他们有哪个温度,然后接受输入并转换并输出所有四个温度。我需要帮助获取用户的输入读入,以便它可以在我的分支,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
答案 0 :(得分:3)
MIPS CPU(没有任何其他常见的)没有"比较字符串"指令,字符串不是本机类型的CPU,指令只处理本机类型,如单词和字节。
"字符串"是连续字符的一定数量(在某处定义,或在数据末尾使用终止符)。什么是#34;一个角色"取决于使用的编码,在您的情况下(MARS模拟器,以及asm编程的简单实践),您可以坚持使用旧的ASCII编码,其中单个字符恰好是一个单字节。 (JFYI:使用现代SW,您将主要使用UTF8编码,就像这个网页一样,单个字符可以有不同的字节数,具体取决于您编码的字形,这使编程任何字符串算法超过UTF8编码的字符串更有趣比你当前的任务。通常太有趣了。)
现在,因为CPU寄存器是"字"大小,这意味着它们是32位"宽",即它们一次最多可以容纳4个ASCII字符(4个字节),因此使用寄存器来存储整个字符串只允许非常小。海峡。而且不是其他的。您可以这样做,但它不实用(beq
除外),因为您可以将字词值0x30303030
= "0000"
与0x31313131
= {{进行比较1}}与"1111"
)。
因此大多数时候在MIPS初学者编程中组装"字符串"遵循模式:某些寄存器包含指向字符串的第一个字母的内存地址(字符串的第一个字节),以及最后一个"字符" string不是任何字母,而是值零,所谓的" null终止符"。
当你想要比较字符串时,你创建循环,它以两个指针开头(两个字符串=两个第一个字母)。将两个地址中的字节加载到一些临时寄存器中(即加载两者的第一个字母),比较一下,如果它们不同,则字符串不同。如果相等,则检查零(两个字符串结束=它们相等)。如果不为零,则将两个地址前进一个,这样它们将指向下一个字母,并循环到开头。
但是在你的情况下,用户只能输入单个字母,并且你只想比较单个字母,所以编写整个循环是一种很大的努力,你可以加载那个单个字母并进行比较。
因此,从顶部阅读您的来源,这些行将得到我的意见:
beq
注释掉了为什么?你应该使用它来限制系统调用(我认为没有设置任何东西,默认值可能是零,所以没有输入发生)。您也可能对syscall(v0=12)"读取字符"感兴趣而不是"读取字符串",但我不确定在MARS中如何向用户呈现(与用户体验相关),但让我们坚持服务v0 = 8"读取字符串"和2字节长的缓冲区。
现在#li $a1, 2
返回后(用户确实输入了字母" f"),地址syscall
的内存将包含由syscall设置的两个字节:102,0。
space
看起来很熟悉,但很难为其他程序员阅读,使用MARS汇编程序,你也可以使用这种编写这个数字的方式:li $t1, 102
- 简单的撇号告诉汇编程序你想要单个ASCII字符的值({{1在MARS中是错误,只能使用单个字符,其他一些汇编程序可能会将' ab'翻译为两个字节值)
下一条未注释的说明是:
li $t1, 'f'
在这里你要问哪个MARS服务?您没有在'ab'
中设置任何值,也不需要任何服务,所以如果您在调试器中单步执行代码,这对您来说没有任何意义,如果您推断将要发生的事情每条指令。
然后来syscall
。
此时v0
等于beq $t0, $t1, fahrenheit
,t1
等于该缓冲区的第一个字节的地址,在编译期间也称为'f'
符号,它等于某个32位值,可能与t0
类似。值space
与0x100000c
的值肯定不相等,因此0x100000c
永远不会跳转到标签102
。
要比较缓冲区内的第一个字母,首先从内存中获取其值,如beq
,从fahrenheit
中的地址加载字节值(高级信息:lb $t2, ($t0)
将签名扩展8位值到32位值.ASCII的基本可打印字符都小于128,因此您不需要处理负值,但如果字母' f'将编码为140,则使用{{ 1}}将该值加载到t0
将产生32位值lb
,而不是lb
...正如我所写,基本ASCII只有7位,所以只有正值,按预期工作,102加载为102)。
然后您可以使用t2
获得更多成功,因为它现在将ASCII字符与ASCII字符进行比较。
您还可以使用MARS MIPS程序集伪指令-116
。 MARS会将其编译为两个本地指令:
140
节省一些打字,这对编程有好处,只要它在阅读时有意义(一旦你开始缩短你的源代码只是为了简短的写作,你在编写源代码时做错了编写代码以便读取,与读取成本相比,写入成本可以忽略不计)。在这种情况下,beq $t2, $t1, fahrenheit
对我来说看起来很可读,所以我更喜欢这样。
这应该足以回答你的问题,明确的问题(如何比较字符串=在循环中,逐个字符)和隐含的问题(如何比较来自用户的单个字母和#39; F')