Benutzerdefinierte Datentypen im Speicher



  • Hallo erneut.

    Natürlich beansprucht g in deinem Beispiel Speicher.

    Laut meinen Professoren und Tutoren, nein.
    Das reine Anlegen also Deklarieren wie in Zeile 7 soll keinerlei Speicher reservieren.

    Folgender Code:

    struct Bruch 
    { 
    int z; 
    int n; 
    };
    
    Bruch b; 
    b.z = 66;
    b.n = 89;
    int a[2] = {25, 29};
    double c = 9.2;
    double* p = &c;
    

    Führt zu folgendem Speicher:

    (ich weiß leider nicht wie man Bilder hochladen kann, ist der Link zu meinem Aufgabenblatt)

    http://gcsc.uni-frankfurt.de/simulation-and-modelling/lectures-courses/prg1-epr/exercises/PRG1_Blatt06.pdf

    Ganz oben, Tabellendarstellung des Speichers. Die benutzerdefinierte Datenstruktur Bruch b nimmt im Speicher bei Deklaration keinerlei Platz in Anspruch.

    Danke für die Hilfe!



  • Beeblebrox schrieb:

    Die benutzerdefinierte Datenstruktur Bruch b nimmt im Speicher bei Deklaration keinerlei Platz in Anspruch.

    Erstens: Der Code in Zeile 7 ist nicht nur eine Deklaration, sondern auch eine Definition.

    Zweitens: b belegt Speicher, und zwar durch seine Member, b.z und b.n. Dass b darüber hinaus keinen Speicher belegt, ist hier zwar richtig, aber erstens ist das nicht immer so, und zweitens ist es nicht relevant. Der Speicher, den die Member von b belegen, gehört natürlich zu dem Speicher, den b selbst belegt, dazu.



  • Beeblebrox schrieb:

    Ganz oben, Tabellendarstellung des Speichers. Die benutzerdefinierte Datenstruktur Bruch b nimmt im Speicher bei Deklaration keinerlei Platz in Anspruch.

    In dem PDF steht doch ganz klar:

    Wird eine neue Variable deklariert, so erhält sie den nächsten freien Speicherplatz (d.h. eins nach dem letzten bereits belegten Speicherplatz).

    Ich vermute irgendwie das es nicht um die Variable b geht, sondern um das struct Bruch in Zeile 1-5. Die Deklaration benötigt nämlich wirklich keinen Speicher, sondern hat nur einen Einfluss auf den Code der für das Anlegen und den Zugriff auf das struct und dessen Elemente generiert wird.



  • Hallo erneut!

    Zweitens: b belegt Speicher, und zwar durch seine Member, b.z und b.n.

    Und woher nimmt er die Information über die Beschaffenheit von b, wenn diese ja im Prinzip nicht gespeichert ist zum Zeitpunkt der Definition / Deklaration?

    Dass b darüber hinaus keinen Speicher belegt, ist hier zwar richtig, aber erstens ist das nicht immer so, und zweitens ist es nicht relevant.

    Die Relevanz entsteht aus dem Anspruch es verstehen zu wollen. Meine Aussage ist ja, dass diese Member eben zum Zeitpunkt der Definition / Deklaration nicht bekannt sein dürften, da diese Signatur ja nirgendwo gespeichert ist. Wann ist das denn nicht so?

    Vielen Dank für deine / eure Hilfe!



  • Beeblebrox schrieb:

    Und woher nimmt er die Information über die Beschaffenheit von b, wenn diese ja im Prinzip nicht gespeichert ist zum Zeitpunkt der Definition / Deklaration?

    Der Compiler weiß zur Compilezeit, wie groß jeder Member ist, und wie weit er von der Adresse des Bruchs selbst enfernt ist. Mehr braucht er nicht.

    Auch wenn erst zur Laufzeit feststehen sollte, wo im Speicher b liegt, so steht doch schon zur Compilezeit fest, wie weit b.z und b.n davon entfernt sind. Und das wird auch fest in das Programm eincompiliert.



  • Du mußt unterscheiden zwischen dem Speicher, den der Compiler während des Kompiliervorgangs (für sich) anlegt und dem Speicher, den das (vom Compiler erzeugte) Programm zur Laufzeit benötigt.

    Die ganzen Deklarationen muß der Compiler natürlich kennen (d.h. dafür Speicher für sich anlegen).
    Das Programm selbst belegt aber bei

    struct Bruch
    {
      int z;
      int n;
    };
    

    zur Laufzeit keinen Speicher, da keine Variable dafür angelegt wird.
    Erst bei

    Bruch b;
    

    erzeugt der Compiler Code dafür, daß das Programm zur Laufzeit den Speicher dafür anlegt (und dessen Standard-Konstruktor aufruft).



  • Ahh .. okay, das hat geholfen. Vielen Dank!

    Jetzt würde mich noch interessieren, welche Anweisungen genau während der Compilezeit und welche während der Laufzeit ausgeführt werden?

    Du mußt unterscheiden zwischen dem Speicher, den der Compiler während des Kompiliervorgangs (für sich) anlegt und dem Speicher, den das (vom Compiler erzeugte) Programm zur Laufzeit benötigt.

    Nochmal kurz in eigenen Worten, nur um sicherzugehen, dass ich das richtig verstehe:

    Das heißt also, dass Informationen wie die benutzerdefinierten Datenstrukturen (also deren Definition) in einem eigenen, während der Compilezeit angelegen Speicher abgelegt werden auf die während der Laufzeit zugegriffen wird?

    Voll cool, dass ihr euch hier mit mir Hohlbrot so auseinandersetzt. 😃



  • Beeblebrox schrieb:

    Ahh .. okay, das hat geholfen. Vielen Dank!

    Voll cool, dass ihr euch hier mit mir Hohlbrot so auseinandersetzt. 😃

    Solange man das Gefühl hat das der Gegenüber auch was lernt und die Antworten wengistens versucht zu verstehen, denke ich, dass es kein Problem darstellt.

    Man hat ja selbst auch irgendwann mal angefangen und dabei nicht immer gleich alles verstanden.



  • Beeblebrox schrieb:

    Das heißt also, dass Informationen wie die benutzerdefinierten Datenstrukturen (also deren Definition) in einem eigenen, während der Compilezeit angelegen Speicher abgelegt werden auf die während der Laufzeit zugegriffen wird?

    Das trifft es nicht ganz.

    Du darfst dir das nicht so vorstellen, dass irgendwo im Speicher der "Bauplan" der Klasse Bruch herumliegt. Das ist gar nicht notwendig. Im kompilierten Programm gibt es keine Datentypen und Variablen mehr, nur noch Adressen.



  • Beeblebrox schrieb:

    Nochmal kurz in eigenen Worten, nur um sicherzugehen, dass ich das richtig verstehe:

    Das heißt also, dass Informationen wie die benutzerdefinierten Datenstrukturen (also deren Definition) in einem eigenen, während der Compilezeit angelegen Speicher abgelegt werden auf die während der Laufzeit zugegriffen wird?

    Nein, die Information des Compilers wird hinterher verworfen, da sie nicht gebraucht wird.

    Der Compiler macht im Prinzip das was du auf dem Aufgabenblatt machen sollst. Er sammelt alle Variablen ein und ordnet ihnen eine oder mehrere Adressen (z.B. bei benutzerdefinierten Datentypen) zu. Jetzt hat der Compiler so eine Tabelle und macht aus der Zeile b.z = 66 einen Maschinenbefehl der Form "schreibe 66 in Adresse 1". Die Adresse 1 entspricht natürlich b.z aber das ist dem Prozessor egal. Der Compiler ersetzt überall b.z und nur b.z durch Adresse 1, hat somit eine eindeutige Zuordnung und es ist ziemlich egal ob der Wert ein Teil von einem benutzerdefinierten Typ ist oder nicht.

    Es gibt dann noch den Fall das man einen ganzen Typ kopiert

    Bruch b = ...;
    Bruch c = b;
    

    Da würde der Compiler z.B. b die Adressen 1/2 geben, c die Adressen 3/4 und entsprechend zwei Maschinenbefehle generieren "Schreibe Wert von Adresse 1 nach Adresse 3" und "Schreibe Wert von Adresse 2 nach Adresse 4".

    Zusammengefasst, der Compiler kennt die Struktur und generiert die entsprechenden kleinschrittigen Befehle das die Information über die Struktur gar nicht mehr benötigt wird.



  • Der Compiler macht im Prinzip das was du auf dem Aufgabenblatt machen sollst. Er sammelt alle Variablen ein und ordnet ihnen eine oder mehrere Adressen (z.B. bei benutzerdefinierten Datentypen) zu. Jetzt hat der Compiler so eine Tabelle und macht aus der Zeile b.z = 66 einen Maschinenbefehl der Form "schreibe 66 in Adresse 1". Die Adresse 1 entspricht natürlich b.z aber das ist dem Prozessor egal. Der Compiler ersetzt überall b.z und nur b.z durch Adresse 1, hat somit eine eindeutige Zuordnung und es ist ziemlich egal ob der Wert ein Teil von einem benutzerdefinierten Typ ist oder nicht.

    Vielen vielen Dank, ihr habt mir alle sehr geholfen und ich denke, dass ich es jetzt verstanden habe .. 😃


Anmelden zum Antworten