wenn ich innerhalb einer C-Funktion drei Variablen deklariere: int a,b,c dann kann ich ja mit denen machen, was ich will. ob ich nun sage: c++;a++; b++; oder b++;a++;c++ ist egal. Ich habe also wärend des Programmierens quasi wahlfreien Zugriff auf die Variablen innherhalb der Funktion. Automatische Variablen werden ja auf dem Stack abgelegt. Wenn nun im Programm kommt: c++; und c ist nicht ganz oben auf dem Stack, wie wird dann auf c zugegriffen? Macht der Herr Compiler das in Maschinensprache etwa so: "Der Will c ändern. Hmm, c ist auf dem Stack an der 3. Position. Da nehm ich erstmal zwei runter und speicher die, hmm, keine Ahnung, inne Ecke? Gut, nun liegt c oben. Les ich aus in ein Register R für späteres bearbeiten des Wertes. Nun pack ich den gelesenen Wert wieder auf den Stack. Noch den Kram aus der Ecke rauf." c ist noch nicht geändert. Nun stelle ich eine berechnung an mit R (das für den Wert von C steht). Das Ergebnis in R wird mit ähnlicher Methodik von vorhin in c geschrieben. Wobei die "ECKE" ein vom Compiler reservierter Speicherbereich ist? Wie groß wird denn so eine "ECKE" wenn man den Speicherbedarf für Controller abschätzen muss? Theoretisch müsste die ECKE ja genauso groß sein wie die (Anzahl lokaler variablen)-1, damit genug Platz zum rumpacken ist. Wird die ECKE dynamisch verwaltet? (Auf nem 8-Bitter wohl eher nicht?).
Du hast den Stack nicht ganz verstanden. Der Stackpointer zeigt zwar immer auf das "oberste" Datum, so dass neue Daten "oben drauf" gespeichert werden können, trotzdem kann auf alle Daten "darunter" zugegriffen werden. Der Compiler weiß, dass c über [Stackpointer + 8] erreichbar ist, weil davor noch 2 * 4 Byte für a und b reserviert sind. (Ich gehe davon aus, dass ein Integer 32 Bit hat und der SP nach unten wächst)
Die Sache mit der Ecke ist reichlich ineffektiv.Wie genau es gemacht wird,hängt sicher auch vom Compiler und den Optimierungsgraden ab.Es wär sicherlich vorstellbar,das in einigen Fällen der Speicherzugriff ganz wegoptimiert und ein Register verwendet wird. Ansonsten wird ein Zeiger relativ zum Stackpointer benutzt.Dazu wird der Stackpointer zu Beginn der Funktion gesichert und alle lokalen Variablen sind dann Offsets zu diesem Wert.Damit können dann auch push/pop zum sichern von Daten oder weitere Funktionsaufrufe genutzt werden,ohne das etwas verloren geht.Dadurch ist es beispielsweise möglich,das eine Funktion sich selbst aufruft. Beim x86 (PC) gibt es sogar ein extra Register um den Stackpointer für lokale Variablen zu sichern (BP Base Pointer)
Super erklärung, Danke euch! Den Stack hatte ich also nicht verstanden, weil ich vom unflexiblen stack in nem 8-Bitter auch auf den PC geschlossen hatte.
Das Grundprinzip des Stacks ist immer das selbe,ein Zeiger-Register wird intern benutzt um nach dem FIFO-Prinzip (First In-First Out) Daten temporär zu sichern.Mir fällt jetzt auf Anhieb keine Architektur ein,wo der Stack nicht nach unten (von höheren zu niederen Adressen hin) wächst. Ob die Architektur nun noch ein zusätzliches Register bereitstellt,um den Stack indirekt zu adressieren hängt davon ab,wie gut sie auf Hochsprachen optimiert ist.Aber meistens spricht nix dagegen,sich einfach auf ein Register zu einigen und diese selbst erstellte Konvention dann konsequent durchzuziehen.Einen Stackpointer der von der Hardware verwaltet wird,gibt es eigentlich immer,schliesslich müssen ja bei Interrupts und Funktionsaufrufen auch Sachen auf dem Stack gesichert werden.
Ein FIFO ist der Stack gerade nicht, LIFO wäre passender.
> Den Stack hatte ich also nicht verstanden, weil ich vom unflexiblen > stack in nem 8-Bitter auch auf den PC geschlossen hatte. Der Stack ist auch auf einem 8-Bitter nicht unflexibel. Was du die ganze Zeit ausser acht lässt ist, dass der Stack in ganz gewöhnlichem Ram residiert. Der Stack ist also eine Datenstruktur, die logisch gesehen etwas höher anzusiedeln ist als reine Speicherzugriffe. Aber da der Stack im RAM realisiert wird, ist es selbstverständlich möglich mittels ganz normaler Speicherzugriffe auf das RAM und damit auf den Stack zuzugreifen (*). Alles was man dazu braucht ist die aktuelle Position des obersten Elements im Stack. Das ist die Basisadresse von der weg gerechnet wird. Wenn ich die habe, kann ich immer mittels gewöhnlicher Speicherzugriffe auf den Stack zugreifen. Das unterscheidet sich konzeptionell in nichts von zb. einem Zugriff auf ein bestimmtes Element eines Arrays. Auch dort kenne ich nur die erste Adresse des Arrayelementes und kann daraus berechnen, wo das Element mit dem Index i im Speicher liegt. Es läuft immer auf dasselbe hinaus: Wenn ich eine Adresse im Speicher kenne, und weis wo in Relation dazu die gesuchten Daten gespeichert sind, kann ich deren Speicheradresse ausrechnen und den Speicherzugriff machen. Manche Prozessoren haben halt dafür noch spezielle Befehle bzw. spezielle Register. Das kann so sein, muss aber nicht. Durch das Vorhandensein dieser Spezialitäten wird nichts an Funktionsumfang gewonnen. Einzig die Art und Weise wie der Zugriff gemacht werden kann, bzw. wie schnell er gemacht werden kann ist anders. Aber Möglichkeiten hab ich deswegen auch nicht mehr. (*) Von Assembler aus. Der Compiler darf das. Als Hochsprachen- programmierer wird dir einiges von den Möglichkeiten genommen um zu verhindern, dass du gegen den Compiler programmierst.
@Frank: Natürlich hast du Recht.Das letzte Element was "oben auf" gelegt wird,ist zugleich das erste,was wieder abgenommen wird.Ab einer gewissen Zeit sollte man einfach schlafen ;)
Okay, dann habe ich es jetzt verstanden :) In nem PIC war der Stack ne eigene Hardware und nicht im Ram. Hab mir jetzt aber auch lieber nen Mega8 geholt.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.