Frage zum Stack

Schnelle objektorientierte, kompilierende Programmiersprache.
forumnewbie
Beiträge: 80
Registriert: Di Jan 15, 2013 9:02 pm

Frage zum Stack

Beitrag von forumnewbie » So Jan 20, 2013 10:51 pm

Hi!

Ich habe mir dieses Tutorial mehrmals durchgelesen: http://www.proggen.org/doku.php?id=c:tutorial:stack aber leider nicht wirklich verstanden. Ich habe dazu deshalb einige Fragen:

Befindet sich der Stack in dem Register des Prozessors? Ich verstehe dann seine Notwendigkeit nicht und von anderen Registern auch nicht. Ein Register ist ein interner Arbeitsspeicher des Prozessors und ist vermutlich deutlich schneller als der Arbeitsspeicher (RAM) auf der Hauptplatine. Wenn der Prozessor z.B. 2+2 rechnet, dann berechnet er das ohne den Arbeitsspeicher und benutzt dann den Arbeitsspeicher nur um ein Ergebnis irgendwo zu speichern? Wenn ja, welcher Arbeitsspeicher wird dazu benutzt - Register oder RAM?
Wenn der Prozessor überhaupt keine Register hätte, würde dann trotzdem alles funktionieren - aber langsamer?

Ich verstehe leider nicht warum man im Stack für ein Programm so viel Platz reservieren muss. Wenn ich richtig verstanden habe, dient der Stack als ein Notizblock. Würde es nicht einfach ausreichen, wenn dort nur die Rücksprungadresse stehen würde? Und wird Stack nur benutzt, wenn man innerhalb von einer Funktion eine weitere aufrufen will, um die Stelle im Code nicht zu vergessen, an der man durch die zweite Funktion unterbrochen wurde?

Danke!

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3125
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Frage zum Stack

Beitrag von cloidnerux » So Jan 20, 2013 11:07 pm

Befindet sich der Stack in dem Register des Prozessors?
Nein, der Stack ist im Arbeitsspeichern,denn jedes Programm braucht seinen eigenen Stack.
Ein Register ist ein interner Arbeitsspeicher des Prozessors und ist vermutlich deutlich schneller als der Arbeitsspeicher (RAM) auf der Hauptplatine. Wenn der Prozessor z.B. 2+2 rechnet, dann berechnet er das ohne den Arbeitsspeicher und benutzt dann den Arbeitsspeicher nur um ein Ergebnis irgendwo zu speichern? Wenn ja, welcher Arbeitsspeicher wird dazu benutzt - Register oder RAM?
Beides. Das Problem ist, dass du dir einen Prozessor zu einfach vorstellst. Ein Prozessor ist eine sehr komplexe Maschine, die sehr viele einzelne Teile besitzt, die allesamt wichtig sind.
Die Register sind z.B ein Teil davon. Diese Register haben einen sehr hohen Stellenwert, da sie nicht einfach nur "Speicher" sind, sondern direkt mit bestimmten Einheiten im Prozessor verdrahtet sind. Dann fordern die einzelnen Prozessorbefehle, dass die zu behandelnden Daten in bestimmten Registern stehen. Du addierst also nicht 2 Werte aus dem Ram, sondern 2 Werte die in zwei Registern stehen. Die Werte können natürlich aus dem Ram in die Register geladen werden.
Also im Grunde ist der Ablauf so: Werte aus dem Ram in die Register laden, befehl ausführen, Ergebnis zurückschreiben.
Das klingt erstmal nach viel sinnloser arbeit, aber wenn du dann 100 befehle hintereinender hast, die auf eben vorher berechnete Daten basieren, dann ersparst du dir das zurückschreiben in den Ram und damit eben eine sehr viel schnellere Berechnung.
Wenn der Prozessor überhaupt keine Register hätte, würde dann trotzdem alles funktionieren - aber langsamer?
Nein.
Ich verstehe leider nicht warum man im Stack für ein Programm so viel Platz reservieren muss. Wenn ich richtig verstanden habe, dient der Stack als ein Notizblock. Würde es nicht einfach ausreichen, wenn dort nur die Rücksprungadresse stehen würde?
Nein. Der Stack ist ein Stapelspeicher, deine Idee wäre eine Variable. Das Problem ist halt, dass du in der Regel bis zu 20-30 ebenen tief Funktionen aufrufst, also sowieso Speicher für eine Dynamische Anzahl an Rücksprungaddressen haben musst. Dann kommen noch alle Funktionsparameter hinzu. Diese werden auch auf den Stack gelegt, wenn ich das richtig in Erinnerung habe, genauso wie den Rückgabewert.
Das bedeutet also insgesamt, dass all dies Notwendig ist.
Wobei man natürlich auch betrachten muss, dass man ewig viel Speicher hat. Was sind schon 500kByte in deinem Ram? Selbst in einem Smartphone hast du 1GB, das sind nochmal mindestens 3 Zehnerpotenzen mehr.
Und wird Stack nur benutzt, wenn man innerhalb von einer Funktion eine weitere aufrufen will, um die Stelle im Code nicht zu vergessen, an der man durch die zweite Funktion unterbrochen wurde?
So in etwa, nur das du nicht nur eine Funktion unterbrichst, sondern wie schon erwähnt sehr viel mehr.

MfG cloidnerux.
Redundanz macht wiederholen unnötig.
quod erat expectandum

forumnewbie
Beiträge: 80
Registriert: Di Jan 15, 2013 9:02 pm

Re: Frage zum Stack

Beitrag von forumnewbie » So Jan 20, 2013 11:56 pm

Vielen Dank für deine Antwort. Du hast absolut recht - ich verstehe leider noch nicht wie der Prozessor die Daten berechnet/verarbeitet und die Erklärungen auf Wikipedia oder anderen Seiten sind für mich zu kompliziert geschrieben, deshalb bin ich erstmal froh, wenn ich das vereinfacht/grob verstehen würde.

Ich versuche dann das Ganze nochmal zusammen zufassen, um zu überprüfen, ob ich das richtig verstehe:

Wenn ich ein Programm starte, dann wird das Programm zunächst mit allen Daten (Funktion(en) mit den ganzen Variablen) in den Arbeitsspeicher in der Maschinensprache (0 und 1) an bestimmten Stellen gespeichert. Dieser Code wird dann mittels des Prozessors richtig bearbeitet und dabei helfen ihm seine Register. Und die Ergebnisse werden dann wieder in den Arbeitsspeicher an eine bestimmte Stelle geschrieben - als Wert einer Variable oder als Rückgabewert einer Funktion. Diese Ergebnisse werden dann im Programm weiter benutzt z.B. für weitere Berechnungen oder Ausgabe auf dem Bildschirm, wofür wieder der Prozessor mit seinen Registern zuständig ist. Und der Stapelregister (stack pointer) des Prozessors weiß wie der Stack im Arbeitsspeicher (RAM) aufgebaut ist und ist für die Bearbeitung der Daten aus dem Stack zuständig.

Ist das ungefähr richtig?

Danke!

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Frage zum Stack

Beitrag von Xin » Mo Jan 21, 2013 12:14 am

forumnewbie hat geschrieben:Wenn ich ein Programm starte, dann wird das Programm zunächst mit allen Daten (Funktion(en) mit den ganzen Variablen) in den Arbeitsspeicher in der Maschinensprache (0 und 1) an bestimmten Stellen gespeichert.
Die Stelle ist im Prinzip egal, muss also nicht "bestimmt" sein.
Wenn Du eine while-Schleife hast, berechnet der Compiler den Abstand zwischen dem Ende der While-Schleife und dem Anfang. Das Programm springt dann einfach am Ende der Schleife den Abstand zwischen Anfang und Ende zurück und landet so also wieder am Anfang der While-Schleife. Wo das Programm dabei im Speicher steht, spielt so keine Rolle.
forumnewbie hat geschrieben:Dieser Code wird dann mittels des Prozessors richtig bearbeitet und dabei helfen ihm seine Register.
Bearbeitet... abgearbeitet. Der Processor liest das Programm Befehl für Befehl und arbeitet diesen ab.

Nehmen wir eine einfache Berechnung: c = a + b + 2;

Code: Alles auswählen

lade Inhalt von Adresse a in Register 1
lade Inhalt von Adresse b in Register 2
addiere Register 2 auf Register 1
schreibe Register 1 an die Adresse von c
Man braucht also einige Register, um zu Rechnen. Je mehr man hat, desto seltener muss man in den Arbeitsspeicher zurückschreiben oder wieder lesen.
Damit das ganze schneller geht, werden daher Teile des Speichers in Caches geschrieben.
forumnewbie hat geschrieben:Und der Stapelregister (stack pointer) des Prozessors weiß wie der Stack im Arbeitsspeicher (RAM) aufgebaut ist und ist für die Bearbeitung der Daten aus dem Stack zuständig.
Wenn Du lokale Variablen benutzt, wird auf den Stackpointer zugegriffen. Eine Variable innerhalb einer Funktion liegt immer relativ zum Stackpointer, zum Beispiel int a liegt 0 Bytes hinter dem Stackpointer, int b 4 Bytes. Der Prozessor muss also noch kurz addieren, aber das läuft heutzutage schon auf eigenen internen Prozessoren vor der eigentlichen CPU ab.

Der Stack regelt also die lokalen Variablen der Funktionsaufrufe und die Rücksprungadressen.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3125
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Frage zum Stack

Beitrag von cloidnerux » Mo Jan 21, 2013 12:17 am

Wenn ich ein Programm starte, dann wird das Programm zunächst mit allen Daten (Funktion(en) mit den ganzen Variablen) in den Arbeitsspeicher in der Maschinensprache (0 und 1) an bestimmten Stellen gespeichert. Dieser Code wird dann mittels des Prozessors richtig bearbeitet und dabei helfen ihm seine Register. Und die Ergebnisse werden dann wieder in den Arbeitsspeicher an eine bestimmte Stelle geschrieben - als Wert einer Variable oder als Rückgabewert einer Funktion. Diese Ergebnisse werden dann im Programm weiter benutzt z.B. für weitere Berechnungen oder Ausgabe auf dem Bildschirm, wofür wieder der Prozessor mit seinen Registern zuständig ist. Und der Stapelregister (stack pointer) des Prozessors weiß wie der Stack im Arbeitsspeicher (RAM) aufgebaut ist und ist für die Bearbeitung der Daten aus dem Stack zuständig.
Das Modell mag in etwa so stimmen, aber egt zu Kompliziert um es zu nutzen.

Für ein meiner Meinung nach sinnvolles Modell ist es irrelevant wie der Prozessor intern Arbeitet, also auch was es mit den Registern auf sich hat. Daher ist für meine Betrachtungsweise nur der Prozessor als "Magische-Wunderkiste" und der Arbeitsspeicher relevant.
Alles wird als Zahl gespeichert, alles ist eine Zahl mit mindestens 8-Bit breite. Ein Prozessorbefehl ist eine Zahl, dein Prozessor rechnet mit Zahlen. Was eine Zahl darstellt, ist durch den Programmkontext gegeben. Wenn dein Prozessor etwas berechnen soll, bekommt er die notwendigen Zahlen sowie den benötigten Befehl.
Um den Programmfluss zu verwalten gibt es den Stack. Auf dem Stack werden Dynamisch alle Notwendigen Zahlen gesichert, die zum Ausführen einer Funktion und zum zurückkehren Notwendig sind. Dazu gehört auch eben entsprechende Pointer auf die Rücksprungadresse, was aber eben auch nur eine Zahl ist.
Damit ergibt sich, dass Zahlen nicht irgendwo hingeschrieben werden, sondern dahin wo du es befiehlst. Also entweder eine Variable mit fester Adresse oder Dynamisch allozierter Speicher.
Daraus ergibt sich z.B auch, dass jeder Zugriff auf Daten über einen Pointer geschieht, der auf die entsprechenden Daten zeigt. Also jede Schreiboperation nur ein Befehl ist, an eine bestimmte Stelle zu schreiben.

Ich übernehme erstmal keine Vollständigkeit dafür, es sollte aber ausreichen.

MfG cloidnerux.
Redundanz macht wiederholen unnötig.
quod erat expectandum

forumnewbie
Beiträge: 80
Registriert: Di Jan 15, 2013 9:02 pm

Re: Frage zum Stack

Beitrag von forumnewbie » Mo Jan 21, 2013 12:34 am

Vielen Dank euch beiden für die Hilfe! Jetzt habe ich eine Vorstellung von dem ganzen Ablauf.

Ich werde jetzt nochmal das Tutorial durchlesen und danach eine praktische Anwendung dazu machen.

Kann man eigene Themen im Forum als "gelöst/beantwortet" markieren?

Danke!

forumnewbie
Beiträge: 80
Registriert: Di Jan 15, 2013 9:02 pm

Re: Frage zum Stack

Beitrag von forumnewbie » Mo Jan 21, 2013 2:36 am

Ich habe ein Beispiel (Youtube-Video) zu Stack gefunden, welches ich leider Aufgrund von ** (Zeiger auf Zeiger?) nicht verstehe. Der Autor sagte, dass man **-braucht, da sonst C immer mit Kopien von Daten (?) arbeitet (das Video ist leider auf Englisch und ich habe deshalb nicht alles in dem Video verstanden). Hier ist der Link zu der Stelle: https://www.youtube.com/watch?v=rwvhluq5sMM . Ich verstehe leider den Sinn von ** nicht. Ein Zeiger zeigt ja bereits auf eine Adresse und somit wird keine Kopie mehr übergeben. Habe mit dem Stack noch große Verständnisprobleme :( .

Code: Alles auswählen

#include <stdio.h>
#include <stdlib.h>

typedef struct Element{
        int *data;
        struct Element *next;
}Element;

int push(Element **stack,int *data);
int pop(Element **stack,int **data);
int createStack(Element **stack);
int deleteStack(Element **stack);

int createStack(Element **stack){
        *stack=NULL;
        return 0;
}

int push(Element **stack,int *data){
        Element *elem;
        elem=(Element*)malloc(sizeof(Element*));

        elem->data=data;
        elem->next=*stack;
        *stack=elem;
        return 0;
}

int pop(Element **stack,int **data){
        Element *elem;
        elem=*stack;

        *stack=elem->next;
        *data=(elem->data);
        free(elem);
        return 0;
}

int deleteStack(Element **stack){
        Element *next;

        while(*stack){
                next=(*stack)->next;
                free(*stack);
                *stack=next;
        }
        return 0;
}

int main(){
        Element *stack;

        int i=5;
        int *o;

        createStack(&stack);
        push(&stack,&i);
        pop(&stack,&o);

        printf("o: %d\n",*o);

        return 0;
}
PS: Stack ist ein spezieller Datenbereich, wo die Daten hintereinander abgelegt werden, richtig? Woher weiß aber das Programm, wann Daten auf einen Stack kommen und wann woandershin (gibt es auch andere Datenbereiche, falls ja - welche?). Man kann anscheinend Daten auch mittels Arrays auf den Stack legen. Woher erkennt aber das Betriebssystem, dass die Daten wie ein Stack gespeichert werden müssen / auf den Stack kommen? Die Funktionen push() und pop() kann man ja nennen wie man will und ich sehe auch kein Schlüsselwort, an dem das Programm erkennen kann, dass es sich um einen Stack handelt.

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3125
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Frage zum Stack

Beitrag von cloidnerux » Mo Jan 21, 2013 8:14 am

PS: Stack ist ein spezieller Datenbereich, wo die Daten hintereinander abgelegt werden, richtig? Woher weiß aber das Programm, wann Daten auf einen Stack kommen und wann woandershin (gibt es auch andere Datenbereiche, falls ja - welche?). Man kann anscheinend Daten auch mittels Arrays auf den Stack legen. Woher erkennt aber das Betriebssystem, dass die Daten wie ein Stack gespeichert werden müssen / auf den Stack kommen? Die Funktionen push() und pop() kann man ja nennen wie man will und ich sehe auch kein Schlüsselwort, an dem das Programm erkennen kann, dass es sich um einen Stack handelt.
Du musst hier 2 Dinge noch unterscheiden, Stack als Datenstruktur und den Programmstack.
Ein Stack ist eine Datenstruktur, auf die du Daten legen kannst, aber immer nur das obere Element herunter nehmen kann. Eine Datenstruktur dient zum verwalten von Daten, seinen es nur einfache Ints oder große Strukturen.
Dein Programmstack hingegen ist auch "nur" ein Stack, hat aber den unterschied dass er für den Prgramfluss notwendig ist.
Ich habe ein Beispiel (Youtube-Video) zu Stack gefunden, welches ich leider Aufgrund von ** (Zeiger auf Zeiger?) nicht verstehe. Der Autor sagte, dass man **-braucht, da sonst C immer mit Kopien von Daten (?) arbeitet (das Video ist leider auf Englisch und ich habe deshalb nicht alles in dem Video verstanden).

Code: Alles auswählen

int push(Element **stack,int *data){
        Element *elem;
        elem=(Element*)malloc(sizeof(Element*));

        elem->data=data;
        elem->next=*stack;
        *stack=elem;
        return 0;
}
In dieser Funktion wird deutlich, was er meint. Du hast einen Pointer auf einen Pointer, der auf eine Struktur zeigt, die vom Typ Element ist. Zum hinzufügen eines neuen Elementes wird in einer Hilfsvariable/pointer "elem" ein neues Element erzeugt, der Pointer auf die Daten gesetzt, das nächste Element im Stack auf das setzten was du übergeben hast und dann den Pointer stack auf das neue oberste Element umschreiben.
Redundanz macht wiederholen unnötig.
quod erat expectandum

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Frage zum Stack

Beitrag von Xin » Mo Jan 21, 2013 11:13 am

forumnewbie hat geschrieben:Ich habe ein Beispiel (Youtube-Video) zu Stack gefunden, welches ich leider Aufgrund von ** (Zeiger auf Zeiger?) nicht verstehe. Der Autor sagte, dass man **-braucht, da sonst C immer mit Kopien von Daten (?) arbeitet (das Video ist leider auf Englisch und ich habe deshalb nicht alles in dem Video verstanden).
Dass ** ein Zeiger auf Zeiger ist richtig.

Tu mir mal den Gefallen und stell Dich in Uservorstellung vor, damit ich einen ungefähren Eindruck habe, wo Du stehst und womit ich Antworten formulieren kann.
forumnewbie hat geschrieben: Hier ist der Link zu der Stelle: https://www.youtube.com/watch?v=rwvhluq5sMM . Ich verstehe leider den Sinn von ** nicht. Ein Zeiger zeigt ja bereits auf eine Adresse und somit wird keine Kopie mehr übergeben. Habe mit dem Stack noch große Verständnisprobleme :( .
Stack steht bei mir auf der Todo-Liste, um da noch Bilder einzufügen, die das Verständnis erleichtern. Heute werde ich das wohl nicht schaffen.

Ein Zeiger auf Zeiger ist meistens eine Implementationsschwäche. Wenn Du eine Struktur Stack anlegst, in der ein Zeiger auf das aktuelle Element im Stack enthalten ist, sollte das reichen. Auf diese Struktur kannst Du natürlich auch zeigen lassen. Wenn man sich die Struktur spart, kann man auch einen Zeiger auf Zeiger zum Stack machen.
Die Struktur kostet nichts und macht die Sache leichter verständlich und besser abprüfbar.

In Deinem Code baust Du einen Stack als verkettete Liste auf. Das ist soweit in Ordnung, aber vermutlich nicht, was Du tun willst, um den Stack zu verstehen.
Im Tutorial wird auf eine andere Seite verwiesen, die die Datenstruktur "Stack" beschreibt: struct:stack. Hast Du die Dir mal angesehen?
forumnewbie hat geschrieben: PS: Stack ist ein spezieller Datenbereich, wo die Daten hintereinander abgelegt werden, richtig? Woher weiß aber das Programm, wann Daten auf einen Stack kommen und wann woandershin (gibt es auch andere Datenbereiche, falls ja - welche?).
Ein Stack hat eine Aufgabe. Im Tutorial hat der Stack die Aufgabe, Funktionsparameter aufzunehmen. Sonst nichts.
Andere Daten, andere Datenbereiche.
forumnewbie hat geschrieben:Man kann anscheinend Daten auch mittels Arrays auf den Stack legen. Woher erkennt aber das Betriebssystem, dass die Daten wie ein Stack gespeichert werden müssen / auf den Stack kommen? Die Funktionen push() und pop() kann man ja nennen wie man will und ich sehe auch kein Schlüsselwort, an dem das Programm erkennen kann, dass es sich um einen Stack handelt.
Das Betriebsystem hat mit dem Stack eigentlich nichts zu tun. Der Stack ist einfach nur eine Datenstruktur, die irgendwie Daten wie ein Stapel aufnimmt und die Daten, die zuletzt draufkamen als erstes wieder zurückgibt. Es gibt Programmiersprachen - wie zum Beispiel C - die einen Stack benutzen, um ihre Funktionsparameter zu sortieren. Andere Programmiersprachen verzichten darauf (zum Beispiel alte Fortranversionen) oder benutzen stattdessen Listen (Lisp). Das OS startet nur das Programm.

@cloidnerux: stack--?
PS: Forget it...
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

forumnewbie
Beiträge: 80
Registriert: Di Jan 15, 2013 9:02 pm

Re: Frage zum Stack

Beitrag von forumnewbie » Di Jan 22, 2013 10:04 pm

Meine Fragen zum Stack-Tutorial:
C ist sehr maschinennah und verwendet daher die gleichen Datenstruktur wie Assembler und damit der Prozessor: einen Stack.
Assembler ist eine Programmiersprache, Prozessor aber eine Hardware. Welcher Zusammenhang besteht zwischen den beiden (Assembler und Prozessor) und dem Stack? Wie sieht überhaupt eine Datenstruktur aus? Welche Aufgaben hat diese und wie arbeitet sie?
Die meisten Prozessoren besitzen ein eigenes Register für den Stack.
Was ist ein Register, wie funktioniert es und wofür brauche ich das für den Stack?
Wie schon beschrieben organisieren viele Programmiersprachen die Ablaufsteuerung über einen Stack. Zu organisieren sind Funktionsaufrufe, deren Parameter und Rückgaben, sowie lokale Variablen, innerhalb einer Funktion definiert werden. Beim Funktionsaufruf werden die Parameter und die Information, wo die Funktion überhaupt gerufen wird, auf eine Notiz geschrieben, damit man am Ende der Funktion an diese Stelle zurückspringen kann. Da am Ende jeder Funktion zur rufenden Funktion zurückgesprungen werden muss und man innerhalb von Funktionen auch andere Funktionen rufen kann, muss hier ein Stapel angelegt werden, wobei auf der obersten Notiz steht, wohin ich zurückspringen muss.
Warum reichen die Rücksprungadressen nicht aus – warum muss man noch zusätzlich die Parameter sowie lokale Variablen einer Funktion sichern? Warum musste man eine ganze Datenstruktur (Stack) dafür erfinden und warum hat ein Prozessor sogar spezielle Stapelregister, die anscheinend nur dazu da sind, um die Daten im Stack zu verwalten/verarbeiten? Würde das nicht mit temporären Variablen ohne Stack funktionieren, die notwendige Informationen für den Funktionsaufruf temporär speichern?
Zusätzlich wird auf der Notiz soviel Platz gelassen, dass alle lokalen Variablen untergebracht werden können, so dass jede Funktion eigene, lokale Variablen definieren kann.
Wenn bereits alle lokalen Variablen und die Parameter gesichert wurden, warum soll man danach noch irgendwelche Variablen definieren? Oder ist damit gemeint, dass bevor die lokalen Variablen gesichert werden können, zuerst für diese Variablen der benötigte Speicherplatz berechnet und reserviert wird, und erst danach werden diese lokalen Variablen gesichert?
Danach wird von einer Notiz abgelesen woher die Funktion aufgerufen wurde, damit der Prozessor die nächsten Anweisungen findet und die Notiz mit dem Ergebnis hinterlegt. Die rufende Funktion kann sich nun das Ergebnis holen. Eine solche Notiz, mit der eine Funktion arbeitet und ihre lokalen Variablen ablegt, nennt man Frame (zu Deutsch Rahmen). Das ist der Rahmen in dem sich eine Funktion mit seinen lokalen Variablen bewegen darf und den sie nicht verlassen darf.
Ist mit der Notiz die Speicherstelle im Stack gemeint, die zum Zwischenspeichern der Ergebnisse verwendet wird? Und mit dem Rahmen ist der Speicherbereich im Stack gemeint, der für eine Funktion reserviert wurde? Und die Funktion kennt die Anfangs- und Endadresse von diesem Speicherbereich – wie ein Array?
Der Compiler hat für die Funktion main zusammengerechnet, dass ihr Frame aus einer lokalen Variable (int temp, 4 Byte) und einem Rückgabewert (int, 4 Byte) besteht.
Ist mit dem Rückgabewert return 0 gemeint oder der Rückgabewert der Funktion add() oder printf()? Und was ist mit der Funktion add(4, 5)? Ich übergebe zwei Konstanten vom Typ int 4 und 5. Sollte man dafür nicht Platz in der main()-Funktion reservieren, wie wir das für die Variable int temp gemacht haben? Wir übergeben ja nur die Kopien dieser zwei Konstanten an die Funktion add(), also existieren diese zwei Konstanten vom Typ int in der Funktion main()? Und in der Funktion printf() übergeben wir eine ganze Zeichenkette und es wird dafür auch kein Platz in der main()-Funktion reserviert.
Dazu kommt die Rücksprungadresse (4 Byte für 32Bit-Systeme oder 8 Byte bei 64Bit-Systemen).
Warum ist Integer bei den 64 bit Systemen größer? Warum hat man das nicht einheitlich gemacht und für 64 bit Systeme spezielle Datentypen eingeführt z.B. int64 ?
Das geht äußerst schnell, da man den Stackpointer, der auf den Speicherbereich des Frames der aktuellen Funktion zeigt, lediglich um 12 bzw. 16 Byte verschiebt. Diese Frames liegen im Speicher also direkt hintereinander.
Sind die Anfangs- und Endadresse für jede Funktion in dem Stack gespeichert und der Prozessor sieht anhand von diesen Adressen wie viel Platz eine Funktion im Stack einnimmt? Und um die Daten aus dem Stack zu bearbeiten benutzt er den Stapelregister? Und sind mit dem Stackpointer einfach die Adressen von Funktionen im Stack gemeint? Also genau so wie ein Array, das eine Anfangs- und eine Endadresse besitzt.
Das geht äußerst schnell, da man den Stackpointer, der auf den Speicherbereich des Frames der aktuellen Funktion zeigt, lediglich um 12 bzw. 16 Byte verschiebt.
Ich verstehe das mit dem „Verschieben“ leider nicht – bzw. kann mir das noch nicht im Kopf vorstellen.
Auch hier hat der Compiler die Framegröße berechnet: 2 Integer als Parameter, 1 Integer als Rückgabe und 1 Integer als lokale Variable: 16 Bytes + Rücksprungadresse ergibt eine Framegröße 20 Bytes (auf 64 Systemen 24 Bytes), die nun auf den Stack „gepusht“ werden (der Stackpointer wird also 20 bzw. 24 Bytes verschoben).
Wie kommt man auf die Zahl von 24 Byte auf 64 bit Systemen – wie wird das berechnet – sollte das nicht 5 Integers * 8 Byte = 40 Byte sein (1 int auf 64 bit = 8 byte)? Verstehe leider wieder nicht, was mit „verschoben“ gemeint ist.
Mit dem Rücksprung wird das Frame vom Stack genommen. Dies nennt man „pop“ - der Stackpointer wird die 20 Byte (bzw. 24 Byte) zurückgeschoben.
Warum wird das vom Stack genommen und warum wird zurückgeschoben?
Der Stack ist natürlich nicht nur für die Programmiersprache selbst vorgesehen, moderne Computer verwenden diese Datenstruktur nur, um die Aufrufreihenfolge der Funktionen zu organisieren. Es steht jedem frei, Stacks auch für eigene Programme zu implementieren.
Wie bzw. warum muss man Stack implementieren? Ich habe es so verstanden, dass der Stack essentiell ist und IMMER verwendet wird, wenn man eine Funktion aufruft – also so gut wie immer, da die meisten Programme nur aus Funktionen bestehen – ohne globalen Variablen. Werden nur globale Variablen ohne Stack verwaltet bzw. irgendwo willkürlich an beliebigen Stellen im Arbeitsspeicher gespeichert?
In der kommenden Lektion werden wir uns damit beschäftigen, wie man Strukturen organisiert und eine neue Datenstruktur kennen lernen: Listen.
Sind Listen also eine andere Datenstruktur? Gibt es dafür auch ein Register im Prozessor? In dem Beispiel oben aus dem Youtube-Video werden aber die Daten mittels von Listen auf den Stack geschrieben, deshalb dachte ich, dass Listen bzw. Strukturen genau so wie Funktionen auf dem Stack liegen? (total verwirrt :shock: )

So, das sind Stellen, die ich in dem Artikel nicht verstehe.
Danke!

Antworten