2017-10-14 2 views
0

Ich schreibe ein Programm, das den Benutzer fragt, welche Temperatur sie haben und dann diese Eingabe nimmt und alle vier Temperaturen konvertiert und ausgibt. Ich brauche Hilfe, die Eingabe meines Benutzers einzulesen, damit es in meinem Zweig, Beq arbeitet. Ich kann nicht erkennen, dass die Eingabe 'f' der gespeicherten Version entspricht.Wie gespeicherte Strings mit eingegebenen Strings verglichen werden - 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

Haben Sie Ihren Code im eingebauten Debugger einmal durchgegangen? Haben Sie in den Dokumenten nach dem von Ihnen verwendeten Syscall gesucht, um festzustellen, ob ein Zeichen in einem Register zurückgegeben wird oder ob es im Speicher gespeichert ist? Sie könnten einen Zeiger mit einer Zahl oder etwas vergleichen. (Sie haben Ihren Code nicht kommentiert, und ich kenne die MIPS-Simulator-Systemnummern nicht von ganz oben.) Wie auch immer ** benutze den Debugger **, es wird es so viel einfacher machen in der Lage zu sein zu überprüfen, was eigentlich in jedem Register ist, das 'beq' betrachtet. –

Antwort

3

MIPS CPU (und keiner von einer anderen gemeinsamen eins) haben keine „strings vergleichen“ Anweisung, string ist nicht nativen CPU-Typ und die Anweisungen beschäftigen nur mit einheimischen Arten, wie Worte und Bytes.

"Zeichenfolge" ist eine bestimmte Anzahl (aufeinanderfolgend definierter Zeichen oder die Verwendung eines Abschlusszeichens am Ende der Daten) aufeinanderfolgender Zeichen. Was "ein Zeichen" ist, hängt von der verwendeten Kodierung ab, in Ihrem Fall (MARS-Simulator und einfaches Üben der ASM-Programmierung) können Sie bei der alten ASCII-Kodierung bleiben, wobei ein einzelnes Zeichen genau ein einzelnes Byte ist. (JFYI: Mit moderner SW werden Sie hauptsächlich in UTF8 Kodierung arbeiten, wie diese Webseite, wo einzelne Zeichen unterschiedliche Anzahl von Bytes haben können, abhängig davon, welche Glyphe Sie kodieren, was die Programmierung eines beliebigen String-Algorithmus über UTF8-kodierten String viel mehr Spaß macht als Ihre aktuelle Aufgabe.Ziemlich oft zu viel Spaß.)

Nun wie die CPU-Register sind "Wort" Größe, das bedeutet, sie sind 32 Bits "breit", dh sie können maximal 4 ASCII-Zeichen auf einmal (4 Bytes), so dass die Verwendung von Registern zum Speichern ganzer Strings nur für sehr sho möglich wäre. str. und sonst nichts. Sie können das tun, aber es ist nicht praktisch (außer die beq würde funktionieren, weil Sie Word-Wert 0x30303030 = "0000" gegen 0x31313131 = "1111" mit beq vergleichen können).

Also die meiste Zeit während der Programmierung in MIPS Anfänger Assembly die "Strings" folgen Muster: einige Register enthält Speicheradresse zeigt auf den ersten Buchstaben der Zeichenfolge (erstes Byte der Zeichenfolge), und die allerletzte "Zeichen" von String ist kein Buchstabe, sondern der Wert Null, der sogenannte "Null-Terminator".

Wenn Sie Zeichenfolgen dann vergleichen möchten, erstellen Sie Schleife, die mit zwei Zeigern (zu den zwei Zeichenfolgen = zu den ersten beiden Buchstaben) beginnt. Lade das Byte von beiden Adressen in ein temporäres Register (d. H. Lade den ersten Buchstaben von beiden), vergleiche das, und, falls sie sich unterscheiden, unterscheiden sich die Strings. Wenn Sie gleich sind, prüfen Sie auf Null (beide Strings beendet = sie sind gleich). Wenn nicht Null, führe beide Adressen um eins weiter, so dass sie auf den nächsten Buchstaben zeigen und zum Anfang zurückkehren.

Aber in Ihrem Fall kann der Benutzer nur einzelnen Buchstaben eingeben, und Sie möchten nur einzelne Buchstaben zu vergleichen, so schreiben ganze Schleife ist eine Art reichlich Aufwand, können Sie nur diesen einzelnen Buchstaben laden und vergleichen Sie das.

So lesen Sie Ihre Quelle von oben, werden diese Zeilen von mir bekommen:

#li $a1, 2 

wird kommentiert, warum? Sie sollten das verwenden, um den Syscall zu begrenzen (ich denke, ohne irgendeinen Wert zu setzen, kann der Standardwert Null sein, so dass keine Eingabe stattfindet). Vielleicht interessiert Sie auch syscall(v0=12) "Lesezeichen" anstelle von "Lesezeichenfolge", aber ich bin mir nicht sicher, wie das für Benutzer in MARS dargestellt wird (User Experience bezogen), aber bleiben wir beim Service v0 = 8 "read string" und 2 Byte langer Puffer.

Jetzt, nachdem syscall zurückkehrt (der Benutzer hat den Buchstaben "f" eingegeben), enthält der Speicher unter der Adresse space zwei Bytes, die von syscall: 102, 0 gesetzt wurden.

li $t1, 102 

kommt mir bekannt vor, aber schwierig für andere Programmierer zu lesen, mit MARS Assembler können Sie verwenden, auch auf diese Weise, dass die Anzahl der Schreiben: li $t1, 'f' - die einfache Apostrophe sagt Ihnen Wert einzelner ASCII-Zeichen Assembler wollen ('ab' fehler in MARS können nur einzelne Zeichen verwendet werden, einige andere Monteuren die ‚ab‘ als zwei Byte-Wert)

Weiter uncommented Anweisung kann übersetzen:

syscall 

Und hier sind Sie gefragt, für die MA RS-Dienst? Sie haben keinen Wert in v0 gesetzt, noch benötigen Sie einen Dienst. Wenn Sie also Ihren Code im Debugger einmal übergehen würden, sollte das für Sie keinen Sinn ergeben, wenn Sie sich überlegen, was mit jeder Anweisung passiert.

Dann kommt .

An diesem Punkt der t1 zu 'f' gleich ist, und t0 gleich Adresse des ersten Bytes des Puffers, der auch als space Symbol während der Kompilierung aliased, die zu einem gewissen 32-Bit-Wert ist, wahrscheinlich ähnlich wie etwas wie 0x100000c . Die Werte 0x100000c vs 102 sind sicherlich nicht gleich, so dass beq niemals auf das Label fahrenheit springen wird.

Um diese Anfangsbuchstabe innerhalb Puffer zu vergleichen, zunächst seinen Wert aus dem Speicher holen, wie lb $t2, ($t0), dass Lasten Wert von Adresse in t0 (erweiterte Info-Byte:. lb den 8-Bit-Wert auf 32-Bit-Wert Vorzeichen erweitern Grund bedruckbaren Zeichen von ASCII sind alle kleiner als 128, so dass Sie keine negativen Werte verarbeiten müssen. Wenn der Buchstabe 'f' jedoch als 140 codiert würde, würde zum Laden dieses Werts in t2 den 32-Bit-Wert -116 und nicht 140 ergeben. Wie ich geschrieben habe, ist das grundlegende ASCII nur 7 Bit, also nur positive Werte, die wie erwartet funktionieren, 102 wird geladen als 102).

Dann können Sie mehr Erfolg mit beq $t2, $t1, fahrenheit haben, da jetzt ASCII-Zeichen gegen ASCII-Zeichen verglichen werden.

Sie können auch MARS MIPS Assembly-Pseudobefehl beq $t2, 'f', fahrenheit verwenden. MARS wird, dass als zwei native Befehle kompilieren:

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

Sie etwas Tipp Speichern, die in der Programmierung ist gut, solange es Sinn macht beim Lesen (wenn Sie Ihren Quellcode zu verkürzen beginnt nur zum Zweck der Kurzes Schreiben, du machst es falsch, bei der Programmierung wird der Quellcode geschrieben, um gelesen zu werden, die Schreibkosten sind im Vergleich zu den Lesekosten vernachlässigbar). In diesem Fall sieht beq $t2, 'f', label für mich ziemlich gut aus, also würde ich das bevorzugen.

Und das sollte genug sein, um beide Fragen zu beantworten, die explizite (wie Strings = in einer Schleife, Zeichen für Zeichen zu vergleichen), und die implizite (wie man diesen einzelnen Buchstaben von Benutzer mit 'f' vergleichen).

+0

Minor Quibble: x86 hat 'repe cmpsb', die Zeichenfolgen vergleicht, und X86 ist ziemlich häufig. Es ist oft nicht die leistungsstärkste Möglichkeit, Strings zu vergleichen, und Sie müssen die Länge einer der Strings kennen, sonst wird es am Ende von beiden nach dem "0" -Byte laufen, wenn sie gleich sind. stos/movs/lods/cmps/scas heißen String-Anweisungen. –

+0

@PeterCordes faire Quibble ... aber im Zusammenhang mit dieser Frage und erwarteten Fähigkeiten des OP Ich denke, es hier in Kommentaren zu halten ist wahrscheinlich am besten, ich habe bereits versucht, die zusätzlichen Informationen in Klammern mit Disclaimer setzen, bin ich noch etwas besorgt das OP wird wie TLDR sogar über wichtige Bits .... OP: Wenn TLDR, hier ist eine Zusammenfassung: ** Debugger verwenden ** – Ped7g

+0

@ Ped7g Vielen Dank! Ich habe es funktioniert. Ihre Antwort war sehr informativ. –

Verwandte Themen