2017-10-14 93 views
0

我正在编写一个程序,询问用户他们有哪个温度,然后接受该输入并转换并输出所有四种温度。我需要帮助让我的用户输入读入,以便它可以在我的分支beq中工作。我无法让它识别输入'f'等于存储的版本。如何将存储的字符串与输入的字符串进行比较MIPS

.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 
+1

您是否在内置调试器中单步执行代码?你是否检查过你正在使用的系统调用的文档,看它是否返回寄存器中的字符,或者是否将它存储在内存中?您可能会将指针与数字或其他内容进行比较。 (你没有评论你的代码,我不知道MIPS模拟器的系统调用数字不在我的头顶。)无论如何**使用调试器**,这将使得能够更容易地检查每个寄存器中'beq'正在看什么。 –

回答

3

MIPS CPU(并且没有其他任何一个共同的),没有“比较字符串”指令,字符串不是原生类型的CPU和说明仅适用于原生类型,如单词和字节处理。

“字符串”是连续字符的一定数量(或在数据末尾定义的某处,或使用终止符字符)。什么是“一个字符”取决于使用的编码,对于您的情况(MARS模拟器,以及简单的asm编程练习),您可以使用旧的ASCII编码,其中单个字符恰好是一个单个字节。 (JFYI:对于现代SW,你将主要使用UTF8编码,就像这个网页一样,单个字符可以有不同的字节数,这取决于你编码的字形,这使得通过UTF8编码的字符串编程任何字符串算法变得更加有趣)

现在CPU寄存器是“字”大小,这意味着它们是32位“宽”,即它们最多可以容纳4个ASCII字符(一次4个字节),所以使用寄存器来存储整个字符串将只允许非常sho。海峡。和别的。你可以这样做,但这是不实际的(除了beq会起作用,因为你可以比较字值0x30303030 = "0000"0x31313131 = "1111"beq)。因此,大部分时间在MIPS初学者程序集编程时,“字符串”是以下模式:某些寄存器包含指向字符串的第一个字母(字符串的第一个字节)的内存地址,以及指向字符串的第一个字符的最后一个“字符”字符串不是任何字母,而是值为零的所谓“空终止符”。

当你想比较字符串,然后,你创建循环,它开始于两个指针(对两个字符串=两个第一个字母)。从两个地址加载字节到一些临时寄存器(即加载两者的首字母),比较一下,如果它们不同,则字符串不同。如果相等,检查零(两个字符串结束=它们相等)。如果不是零,则将两个地址前进一个,以便它们指向下一个字母,并循环到开头。

但在您的情况下,用户只能输入单个字母,而您只想比较单个字母,因此编写整个循环需要花费很多精力,您可以加载该单个字母并进行比较。

所以阅读从上源,这些线路将得到我的意见:

#li $a1, 2 

被注释掉为什么呢?你应该使用它来限制系统调用(我认为没有设置任何默认值可能为零,所以没有输入发生)。你也许会对syscall(v0=12)“读取字符”而不是“读取字符串”感兴趣,但我不确定这是如何在MARS中呈现给用户的(用户体验相关),但让我们坚持服务v0 = 8“读取字符串”和2个字节长的缓冲区。

现在在syscall返回(用户确实输入字母“f”)后,地址space的内存将包含syscall:102,0设置的两个字节。

li $t1, 102 

看起来很熟悉,但难以阅读的其他程序员,与MARS汇编也可以用书面数是这样的:li $t1, 'f' - 简单的撇号告诉汇编你想单个ASCII字符的值('ab'是错误在MARS,只有单个字符,可以使用一些其他的汇编可以翻译“AB”为两个字节值)

下一页注释掉的指令是:

syscall 

在这里,你所要求的其中MA RS服务?您没有在v0中设置任何值,也不需要任何服务,因此如果您在调试器中单步执行代码,那么如果您推断每条指令会发生什么情况,则这对您来说应该没有意义。

然后来到beq $t0, $t1, fahrenheit

在这一点上t1等于'f',和t0等于缓冲器,在编译期间也别名为space符号,其等于大约32比特值的第一个字节的地址,大概类似于像0x100000c 。值0x100000c vs 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。火星将编译为两个原生指令:

addi $at, $zero, 102 # 102 = 'f', $at = $1, $zero = $0 
beq $at, $t2, fahrenheit 

节省您的一些打字,这是在规划好,只要它是有意义的,而读(一旦你将开始缩短你的源代码只是为目的简短的写作,你做错了,编程中的源代码被写入被读取,写入成本与阅读成本相比可以忽略不计)。在这种情况下,beq $t2, 'f', label看起来对我来说很可读,所以我更喜欢这样。

而且这应该足以回答你的问题,明确的问题(如何比较字符串=在循环中,逐字符)和隐式的问题(如何比较用户的单个字母与'f' )。

+0

minor quibble:x86有'repe cmpsb',它比较字符串,而x86很常见。它通常不是比较字符串的最高性能方式,而且您必须知道其中一个字符串的长度,否则它们将在两个字符相同时结束时超过“0”字节。 stos/movs/lods/cmps/scas被称为字符串指令。 –

+0

@PeterCordes公平的狡辩......但由于这个问题的背景和OP的预期技能水平,我认为在评论中保留它可能是最好的,我已经试图将额外的信息放在带有免责声明的括号中,但我仍然有些担心OP会像TLDR一样超过重要的位... OP:如果TLDR,这里是总结:**使用调试器** – Ped7g

+0

@ Ped7g谢谢!我得到了它的工作。您的回复非常丰富。 –

相关问题