如何将存储的字符串与输入的字符串进行比较-MIPS [英] How to compare stored strings with inputted strings-MIPS

查看:108
本文介绍了如何将存储的字符串与输入的字符串进行比较-MIPS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个程序,询问用户他们的温度,然后获取该输入并转换和输出所有四个温度.我需要帮助让我的用户输入读入,以便它可以在我的分支中工作,beq.我无法将输入 'f' 识别为等于存储的版本.

I'm writing a program that asks the user which temperature they have and then takes that input and converts and outputs all four temperatures. I need help getting my user's input read-in so that it will work in my branch, beq. I can't get it to recogize the input 'f' as equal to the stored version.

.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 的原生类型,指令只处理原生的类型,如字和字节.

MIPS CPU (and none of any other common one) has no "compare strings" instruction, string is not native type of CPU and the instructions deal only with native types, like words and bytes.

"String" 是一定数量(在某处定义,或在数据末尾使用终止符)的连续字符.什么是一个字符"取决于使用的编码,在您的情况下(MARS 模拟器和 asm 编程的简单实践),您可以坚持使用旧的 ASCII 编码,其中单个字符恰好是一个单字节.(JFYI:使用现代软件,您将主要使用 UTF8 编码,就像这个网页所做的那样,其中单个字符可以有不同数量的字节,这取决于您编码的字形,这使得通过 UTF8 编码的字符串编程任何字符串算法变得更加有趣比你当前的任务还多.通常太有趣了.)

"String" is certain amount (either defined somewhere, or using terminator character at end of data) of consecutive characters. What is "one character" depends on used encoding, in your case (MARS simulator, and simple practice of asm programming) you can stick with the old ASCII encoding, where single character is exactly one single byte. (JFYI: with modern SW you will mostly work in UTF8 encoding, like this web page does, where single character can have different amount of bytes, depending on which glyph you encode, which makes programming any string algorithm over UTF8 encoded string lot more fun than your current task. Quite often too much fun.)

现在由于 CPU 寄存器是字"大小,这意味着它们是 32 位宽",即它们一次最多可以容纳 4 个 ASCII 字符(4 个字节),因此使用寄存器来存储整个字符串将允许只为非常sho.海峡和_没有别的.您可以这样做,但它不切实际(除了 beq 可以工作,因为您可以将字值 0x30303030 = "0000"0x31313131 = "1111" with beq).

Now as the CPU registers are of "word" size, that means they are 32 bits "wide", i.e. they can hold at most 4 ASCII characters at once (4 bytes), so using registers to store whole string would allow only for very sho. str. and_ noth else. You can do that, but it's not practical (except the beq would work, because you can compare word value 0x30303030 = "0000" against 0x31313131 = "1111" with beq).

因此,在 MIPS 初学者汇编中编程时,大部分时间字符串"遵循以下模式:某些寄存器包含指向字符串第一个字母(字符串的第一个字节)的内存地址,以及字符串的最后一个字符"不是任何字母,而是零值,即所谓的空终止符".

Thus most of the time while programming in MIPS beginners assembly the "strings" are following pattern: some register contains memory address pointing to the first letter of string (first byte of string), and the very last "character" of string is not any letter, but value zero, the so called "null terminator".

当你想比较字符串时,你创建循环,它以两个指针开始(指向两个字符串=指向两个第一个字母).将两个地址中的字节加载到某个临时寄存器中(即加载两者的第一个字母),将其与字符串进行比较,如果它们不同,则字符串不同.如果相等,则检查是否为零(两个字符串都结束 = 它们相等).如果不为零,则将两个地址都加一,以便它们指向下一个字母,并循环到开头.

When you want to compare strings then, you create loop, which starts with two pointers (to the two strings = to the two first letters). Load byte from both addresses into some temporary register (i.e. loading first letter of both), compare that, against, if they differ, the strings differ. If equal, check for zero (both strings ended = they are equal). If not zero, advance both addresses by one, so they will point to the next letter, and loop to the beginning.

但在您的情况下,用户只能输入单个字母,而您只想比较单个字母,因此编写整个循环是一种繁重的工作,您只需加载单个字母并进行比较即可.

But in your case the user can enter only single letter, and you want to compare only single letter, so writing whole loop is sort of abundant effort, you can just load that single letter and compare that.

所以从顶部阅读你的来源,这些行会得到我的评论:

So reading your source from top, these lines will get my comments:

#li $a1, 2

为什么被注释掉?您应该使用它来限制系统调用(我认为不设置任何内容,默认值可能为零,因此不会发生任何输入).您也可能对 syscall(v0=12) 感兴趣字符"而不是读取字符串",但我不确定在 MARS 中如何向用户呈现它(与用户体验相关),但让我们坚持使用服务 v0=8读取字符串"和 2 字节长的缓冲区.

is commented out why? You should use that to limit the syscall (I think without setting anything the default value may be zero, so no input happens). Also you may be interested into syscall(v0=12) "read character" instead of "read string", but I'm not sure how that is presented toward user in MARS (user experience related), but let's stick with service v0=8 "read string" and 2 byte long buffer.

现在syscall返回后(用户输入了字母f"),地址space的内存将包含两个由syscall设置的字节:102, 0.

Now after syscall returns (user did enter the letter "f"), the memory at address space will contain two bytes set by syscall: 102, 0.

li $t1, 102

看起来很熟悉,但对于其他程序员来说很难阅读,使用 MARS 汇编程序,您也可以使用这种写数字的方式:li $t1, 'f' - 简单的撇号告诉汇编程序您想要单个 ASCII 字符的值('ab' 在 MARS 中是错误的,只能使用单个字符,其他一些汇编程序可能会将 'ab' 转换为两个字节的值)

Looks familiar, but difficult to read for other programmer, with MARS assembler you can use also this way of writing that number: li $t1, 'f' - the simple apostrophes tells assembler you want value of single ASCII character ('ab' is error in MARS, only single char can be used, some other assemblers may translate the 'ab' as two byte value)

下一个未注释的指令是:

Next uncommented instruction is:

syscall

这里你问的是哪个 MARS 服务?你没有在 v0 中设置任何值,也不需要任何服务,所以如果你在调试器中单步执行你的代码,这对你来说应该没有意义,如果你能推断出正在发生的事情每条指令.

And here you are asking for which MARS service? You didn't set any value in v0, nor you need any service, so if you would single step over your code in debugger, this should make no sense to you, if you reason what is going happen with each instruction.

然后是beq $t0, $t1, fahrenheit.

此时 t1 等于 'f't0 等于该缓冲区的第一个字节的地址,也在编译期间别名为 space 符号,它等于一些 32 位值,可能类似于 0x100000c 之类的东西.0x100000c102 的值肯定不相等,因此 beq 永远不会跳转到标签 fahrenheit.

At that point the t1 is equal to 'f', and t0 is equal to address of first byte of that buffer, also aliased as space symbol during compilation, which is equal to some 32 bit value, probably similar to something like 0x100000c. The values 0x100000c vs 102 certainly doesn't equal, so that beq will never jump to label fahrenheit.

要比较缓冲区内的第一个字母,首先从内存中获取它的值,例如 lb $t2, ($t0),从 t0 中的地址加载字节值(高级信息:lb 会将 8 位值符号扩展为 32 位值.ASCII 的基本可打印字符都小于 128,因此您不需要处理负值,但如果字母'f' 将编码为 140,使用 lb 将该值加载到 t2 将产生 32 位值 -116,而不是 140 ...正如我写的,基本的 ASCII 只有 7 位,所以只有正值,按预期工作,102 加载为 102).

To compare that first letter inside buffer, first fetch its value from memory, like lb $t2, ($t0), that loads byte value from address in t0 (advanced info: lb will sign-extend the 8 bit value to 32 bit value. Basic printable characters of ASCII are all smaller than 128, so you will not need to deal with negative values, but if letter 'f' would encode as 140, using lb to load that value into t2 would produce 32 bit value -116, not 140 ... as I wrote, basic ASCII is only 7 bit, so only positive values, which work as expected, 102 is loaded as 102).

然后您可以使用 beq $t2, $t1, fahrenheit 获得更多成功,因为现在它将比较 ASCII 字符与 ASCII 字符.

Then you can have more success with beq $t2, $t1, fahrenheit, as now it will compare ASCII character against ASCII character.

你也可以使用MARS MIPS汇编伪指令beq $t2, 'f', fahrenheit.MARS 会将其编译为两条本机指令:

You can also use MARS MIPS assembly pseudo instruction beq $t2, 'f', fahrenheit. MARS will compile that as two native instructions:

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

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

Saving you some typing, which is good in programming, as long as it makes sense while reading (once you will start to shorten your source code just for the purpose of short writing, you are doing it wrong, in programming the source code is written to be being read, the writing cost is negligible compared to the reading costs). In this case beq $t2, 'f', label looks quite readable to me, so I would prefer that.

这应该足以回答您的两个问题,明确的问题(如何在循环中逐个字符地比较字符串 =)和隐含的问题(如何将用户的单个字母与 'f' 进行比较).

And that should be enough to answer both your questions, the explicit one (how to compare strings = in a loop, character by character), and the implicit one (how to compare that single letter from user against 'f').

这篇关于如何将存储的字符串与输入的字符串进行比较-MIPS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆