Okay, es gab ein paar Bugs. Ich habe die Quelle kommentiert und "BUG:" hinzugefügt, um sie zu beleuchten. Ich habe dann eine aufgeräumt und korrigierte Version
Hier ist dein Original-Code - keine Fehlerbehebungen, nur Anmerkungen [bitte unentgeltlichen Stil Bereinigungs verzeihen]:
# int
# count(int a[], int n, int x)
# {
# int res = 0;
# int i = 0;
# int j = 0;
# int loc[n];
#
# for (i = 0; i != n; i++) {
# if (a[i] == x) {
# res = res + 1;
# loc[j] = i;
# j = j + 1;
# }
# }
#
# return res, loc;
# }
.data
a: .word 5,6,7,8,9,10
n: .word
x: .word
res: .word 0
i: .word 0
jj: .word 0
loc: .space 40
nl: .asciiz "\n"
.text
.globl main
main:
la $s0,a
lw $s1,res
lw $s2,x
lw $t0,i
lw $t1,jj
lw $t2,n
la $s3,loc
li $t4,6 # BUG: extraneous (gets trashed below)
start:
sll $t3,$t0,2 # get i << 2
add $t5,$t3,$s0 # get &a[i]
lw $t4,0($t5) # fetch it
# BUG: we're comparing a[i] against i but we want to compare against x
# _and_ we want to flip the sense of the branch
beq $t0,$t4,start # is it a match? if yes, loop
addi $t0,$t0,1 # increment i
beq $t0,$t2,exit # i == n? if no, loop. if yes, exit
# BUG: the indexing here is wrong
addi $s1,$s1,1 # j += 1
sll $t7,$t1,2 # get jj << j
add $t6,$s3,$t7 # &loc[jj << j] (BUG: we want &loc[j])
sw $t0,0($t6) # set it to i
addi $t1,$t1,1 # jj += 1
# BUG: we should loop here and _not_ fall through
exit:
# print j (with newline)
li $v0,1
add $a0,$s1,$zero
syscall
li $v0,4
la $a0,nl
syscall
# print _address_ of loc[0]
# BUG: if we care to print anything, we should print the _values_ of the
# whole array
li $v0,1
# BUG: this should be a0 and _not_ a1
###add $a1,$s3,$zero
add $a0,$s3,$zero
syscall
li $v0,4
la $a0,nl
syscall
li $v0,10 # exit program
syscall
Hier ist die gereinigte up und korrigierte Version. Ich musste ein wenig umstrukturieren und vereinfachen, damit es funktioniert, also könnte es auf den ersten Blick ein bisschen "fremd" erscheinen. Ich habe jedoch versucht, Ihre Registrierung so weit wie möglich zu behalten.
I erhöhte auch die Größe des a
Array und eine Benutzereingabeaufforderung für die x
Wert hinzugefügt:
# int
# count(int a[], int n, int x)
# {
# int i = 0;
# int j = 0;
# int loc[n];
#
# for (i = 0; i != n; i++) {
# if (a[i] == x) {
# loc[j] = i;
# j += 1;
# }
# }
#
# return j, loc;
# }
.data
a: .word 5,6,7,8,9,10
.word 5,6,7,8,9,10
.word 5,6,7,8,9,10
.word 5,6,7,8,9,10
.word 5,6,7,8,9,10
ae:
loc: .space 1000
prompt: .asciiz "Enter x value: "
msgnl: .asciiz "\n"
msgj: .asciiz "j: "
msgloc: .asciiz "loc: "
.text
# main -- main program
#
# RETURNS [sort of as this is a main program]:
# s1 -- j value (count of elements in "loc")
# loc -- filled in indexes into "a" array of matches to x
#
# registers:
# s0 -- a (base address of "a" array)
# t2 -- n (number of elements in "a" array)
#
# s2 -- x (value to match)
# t0 -- i (current index into "a" array)
# s3 -- loc (base address of "loc" array)
# s1 -- j (current index into "loc" array)
#
# t6 -- quick temporary [reusable]
# t7 -- used in array offset/index calculations [reusable]
.globl main
main:
# prompt for x value
li $v0,4 # syscall: print string
la $a0,prompt
syscall
# read in x value
li $v0,5 # syscall: read integer
syscall
move $s2,$v0
# get address of "a" array and compute length
la $s0,a # get &a[0]
la $t2,ae # get address of &a[n]
sub $t2,$t2,$s0 # get number of bytes in a
srl $t2,$t2,2 # get number of words in a (i.e. n)
li $t0,0 # i = 0
li $s1,0 # j = 0
la $s3,loc # base address of loc array
# main matching loop
loop:
sll $t7,$t0,2 # get i << 2
add $t7,$t7,$s0 # get &a[i]
lw $t6,0($t7) # fetch from it
bne $t6,$s2,next # a[i] == x? if no, advance to next element
# add new "i" value to loc array
sll $t7,$s1,2 # get j << 2
add $t7,$s3,$t7 # &loc[j << 2]
sw $t0,0($t7) # store i into loc
addi $s1,$s1,1 # j += 1
next:
addi $t0,$t0,1 # i += 1
blt $t0,$t2,loop # i < n? if yes, loop (or, we're done)
# done with calculation/fill loop
done:
la $s6,msgj # get prefix string
move $s7,$s1 # get j
jal prtnum # pretty print the number
blez $s1,exit # bug out if _no_ values in loc
# prepare to print all values of loc
la $t6,loc # base address of "loc"
li $t7,0 # initial index
# loop and print all values of loc
prtlocloop:
la $s6,msgloc # prefix string
lw $s7,($t6) # get loc[...]
jal prtnum # pretty print the number
add $t6,$t6,4 # increment address
add $t7,$t7,1 # increment index
blt $t7,$s1,prtlocloop # done? if no, loop
exit:
li $v0,10 # exit program
syscall
# prtnum -- print a number with a prefix string on a single line
#
# arguments:
# s6 -- prefix string
# s7 -- value to print
#
# registers:
# v0 -- syscall number [trashed]
# a0 -- syscall argument [trashed]
prtnum:
li $v0,4 # syscall: print string
move $a0,$s6 # string to print
syscall
li $v0,1 # syscall: print integer
move $a0,$s7 # value to print
syscall
li $v0,4 # syscall: print string
la $a0,msgnl
syscall
jr $ra # return
UPDATE:
Was genau ist der Unterschied zwischen print
und prtnum
?
print
ist die Bezeichnung für den Anfang der Schleife, die die Werte in loc
druckt. prtnum
ist Unterprogramm/Funktion, die den Druck einer einzigen Nummer ausführt.
Ich habe prtnum
hinzugefügt, um die Verwendung einer Funktion zu demonstrieren und unnötige Replikation von Code zu vermeiden.
Können sie nicht richtig zusammengeführt werden?
Sicher, mit einigen Vorbehalten. Ich habe einen leichten/kosmetischen Schnitt gemacht, um die Dinge klarer zu machen. Insbesondere habe ich print:
in prtlocloop:
umbenannt, um seine Rolle klarer zu machen.
The syscall(1)
für "print integer" druckt nur die ganze Zahl, aber tut sie nicht alle Leerzeichen oder Newline hinzufügen zu trennen (das heißt, es ist genau wie printf("%d",a0)
). Also, wir brauchen etwas.
Ursprünglich hatte ich gerade die syscall(print_integer)
. Damit erhalten wir eine "sehr lange" Nummer. Dann fügte ich syscall(4)
hinzu, um eine neue Zeile zu drucken. Das war in Ordnung, außer dass die Ausgabe ein wenig verwirrend war, welcher Wert j
war und welche die loc
Werte waren.
(1) Also, ich habe die "Präfix" Zeichenfolge hinzugefügt. Also, das wurden drei syscalls für jede Nummer.
(2) Dies wurde in zwei Stellen verwendet: Zum Drucken j
und die loc
Werte zu drucken.
Gleicher Code an zwei oder mehr Stellen. Das ist das Standardkriterium für "split out code to function" in beliebigen Sprache. Es ist eine Design-/Stilwahl [also gibt es keine absolute Antwort].
Also, mit (1) und (2), ich habe es auf die prtnum
Funktion verschoben. Eigentlich schrieb ich die prtnum
Funktion zuerst, weil ich bereits die Struktur kannte, und fügte das Präfix Argument nach der Ausgabe "sah hässlich" [zu mir].
Als ich es zuerst codiert habe, habe ich "j: "
für j
verwendet und ein " "
Präfix für loc
verwendet. Es sah immer noch ein bisschen funky aus. Also habe ich das Präfix auf "loc: "
geändert, um konsistent zu sein.
Könnte es inline sein? Sicher. Neben dem Ausdruck der Zahl selbst müssen wir noch einen Separator hinzufügen. Also, wir brauchen zwei syscalls pro Nummer, um es zu tun.
Der Separator könnte ein Leerzeichen sein, wenn wir alle Zahlen auf die gleiche Zeile schreiben wollen. Gut für kurze Vektoren. Dies würde eine geringfügige Änderung des Codes erfordern, so wie er jetzt existiert, und wir müssten eine Endausgabe von Newline hinzufügen, um die Zeile zu schließen. Bei längeren Arrays [die möglicherweise nicht in eine einzige Zeile passen] ist einer pro Zeile [wahrscheinlich] aufgeräumter.
Wir mussten nur j
und loc
drucken. Wenn das Problem besagt, dass wir a
, dann j
und dann loc
drucken mussten, wäre ich in die andere Richtung gegangen.
Ich hätte prtlocloop
in eine andere Funktion (z. B. prtarray
) geändert, die auf dem gegebenen Array Schleife und prtnum
für jedes Element aufrufen würde.
Der erste Schritt war, die Berechnungsschleife korrekt zu bekommen. Die zweite war das Drucken. Aber manchmal müssen sie zusammen gemacht werden. (d. h.) Wie können Sie etwas debuggen, das Sie nicht sehen können?
Mit korrekter Berechnung können Sie den Ausgabedruck beliebig umkodieren. Die prtnum
war nur meine Weg. Aber es ist durch keine bedeutet die einzige Möglichkeit.
über die grundlegenden Mechanismen der Zusammenarbeit mit den asm Anweisungen arbeiten, sind die Wahlen wie in einer anderen Sprache, [insbesondere C]. Kommentar gut, wählen Sie die einfachste und effektivste Möglichkeit, den Code zu entwerfen/zu teilen, verwenden Sie beschreibende Variablennamen usw. Kommentare sollten "Absicht", das "was/warum" zeigen. Die asm-Anweisungen sind das "Wie".
Randbemerkung: Einige OPs haben ernsthafte Schwierigkeiten hatte, zu verstehen, wie sll
[die Sie bereits verstehen] funktioniert. Sie haben einfach nicht "verstanden", dass eine Linksverschiebung um 2 wie eine Multiplikation mit 4 war und konvertiert einen Indexwert in Byte/Adressoffset. So, Sie können bereits dem Spiel voraus sein ...
Gestern gab ich eine Antwort für eine Mips-Frage, wo ich den anderen Weg ging und empfahl, zwei Funktionen inlining. Das Problem bestand darin, sin(x)
unter Verwendung einer Taylor-Reihenentwicklung [Summierung der Terme] des Formulars zu berechnen: x**(2n)/factorial(2n-1)
.
Mit Inlining war es möglich, Teilergebnisse aus dem vorherigen Begriff in der Reihe ohne wieder zu verwenden, müssen jeden Begriff von Grund auf neu berechnen. Dies wäre mit mehreren Funktionen nicht möglich gewesen.
Ich habe den Mips-Code nicht geschrieben, aber ich schrieb den C/Pseudo-Code: mips program to calculate sin(x) Der resultierende Mips-Code wäre [wahrscheinlich] einfacher gewesen und würde definitiv schneller laufen.
'int loc [];' im C-Code macht keinen Sinn. – EOF
'return res, loc;' ist, nun, rein * technisch * ist es gültig C - aber es dient keinem klaren Zweck. Was soll diese Linie tun? – usr2564301
@RadLexus In MIPS asm, selbst mit Standardkonvention, können Sie _zwei_ Werte (in 'v0' und' v1') zurückgeben. Mit internen Konventionen kann jeder FNC so viele "Rückgabe" -Werte in so viele Register setzen, wie man möchte. Das C hier ist mehr wie Pseudocode für die vorgeschlagene asm –