如何比较存储的字符串与输入的字符串-MIPS

时间:2017-10-14 01:24:16

标签: assembly mips mars-simulator

我正在编写一个程序,询问用户他们有哪个温度,然后接受输入并转换并输出所有四个温度。我需要帮助获取用户的输入读入,以便它可以在我的分支,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 

1 个答案:

答案 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, fahrenheitt1等于该缓冲区的第一个字节的地址,在编译期间也称为'f'符号,它等于某个32位值,可能与t0类似。值space0x100000c的值肯定不相等,因此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')