Wie wird eine Struktur im Speicher angelegt?
-
Servus,
folgender Ausgangscode:
struct test { int a; char b; } struct test t;
Wie sieht diese Struktur auf dem Stack aus? Die Reihenfolge der Member ist nicht definiert, aber liegt die Struktur als ein "Speicherblock" zusammen (ich denke schon) und geschieht da sonst noch irgendwas nennenswertes?
-
struct_im_speicher schrieb:
Wie sieht diese Struktur auf dem Stack aus?
Die Instanz t der Struktur test liegt nicht auf dem Stack, wenn du sie global definierst.
struct_im_speicher schrieb:
Die Reihenfolge der Member ist nicht definiert, aber liegt die Struktur als ein "Speicherblock" zusammen (ich denke schon) und geschieht da sonst noch irgendwas nennenswertes?
Doch, die Reihenfolge der Member ist im C-Standard definiert. Google mal, du solltest genug Material dazu finde.
Nennenswert wäre vielleicht noch Alignment. Auch da sollte Google einiges dazu auspucken
-
struct_im_speicher schrieb:
Wie sieht diese Struktur auf dem Stack aus?
- Die Reihenfolge ist definiert (und zwar genau zur Reihenfolge, wie du sie deklariert hast).
- Es kann beliebig viel Padding eingefügt werden, d.h. zwischen den einzelnen Membern dürfen Füllbytes sein, die nicht benutzt werden.
- a liegt garantiert am Anfang der Struktur.
-
Die Reihenfolge ist definiert.
Die struct liegt als ein Block im Speicher.
Es werden noch Paddingbytes eingebaut, damit der Prozessor schneller auf die Elemente zugreifen kann.
-
...
-
struct_im_speicher schrieb:
Servus,
folgender Ausgangscode:
struct test { int a; char b; } struct test t;
Wie sieht diese Struktur auf dem Stack aus? Die Reihenfolge der Member ist nicht definiert, aber liegt die Struktur als ein "Speicherblock" zusammen (ich denke schon) und geschieht da sonst noch irgendwas nennenswertes?
Stack ist nicht immer der Fall!
Vereinfachte virtuelle Speicheraufteilung von einem Prozess:
+------+-------+------+------+ | Code | Daten | Heap | Stack| +------+-------+------+------+
struct test t1; // global --> Daten int main() { struct test t2; // lokal --> Stack struct test *t3=malloc(sizeof(struct test)); // dyn. Speicher --> Heap }
-
Da kommt mir doch gleich auch eine Frage auf: Wenn Füllbytes zwischen den Strukturelementen eingefügt werden, dann ändert sich doch die Größe der Struktur im Speicher(Strukturadresse + Strukturelement + Füllbytes) Reserviert malloc dann den Speicher mit Füllbytes oder ohne?
-
declare schrieb:
Da kommt mir doch gleich auch eine Frage auf: Wenn Füllbytes zwischen den Strukturelementen eingefügt werden, dann ändert sich doch die Größe der Struktur im Speicher(Strukturadresse + Strukturelement + Füllbytes) Reserviert malloc dann den Speicher mit Füllbytes oder ohne?
malloc reserviert so viel wie du angibst und weiß nichts von typen oder paddingbytes. man verwendet aber oft sizeof(type) als argument für malloc, und wenn du damit ein wenig rumspielst wird dir auffallen, dass sich die
größe von typen eben oft nicht durch einfaches addieren der einzelnen feldgrößen ergibt. die paddingbytes zählen natürlich mit rein. ansonsten würde so gut wie alles schießgehen
-
Ah, also ist sizeof hier der Zaubermeister, der auch gleich die Füllbytes mit rein rechnet.
-
declare schrieb:
Da kommt mir doch gleich auch eine Frage auf: Wenn Füllbytes zwischen den Strukturelementen eingefügt werden, dann ändert sich doch die Größe der Struktur im Speicher(Strukturadresse + Strukturelement + Füllbytes) Reserviert malloc dann den Speicher mit Füllbytes oder ohne?
malloc gibt dir mit großer wahrscheinlichkeit einen größeren Speicherblock als du eigentlich möchtest.
Vom Betriebssystem bekommt man nur seitenweise (4096byte) Speicher. malloc holt sich also gleich ein bisschen mehr, und organisiert sich den Speicher dann selbst.
Oft wird der Heap in Pools eingeteilt, mit 32byte, 64byte, 128byte, ... Größe.
Willst du 100byte, so bekommst du dann eben 128byte.Du kannst mit sbrk() ja mal schauen, an welcher Addresse das Heap Ende liegt.
Dann rufst du erstmalig malloc(100) auf, und rufst nochmal sbrk auf, um zu sehen, wo das Heap Ende jetzt liegt.
Du wirst sehen, malloc hat sich einiges an Speicher geholt.Schau dir z.B. mal http://en.wikipedia.org/wiki/Buddy_memory_allocation an, das ist ein Algorithmus wie Speicher von malloc verwaltet werden kann.
-
Wie rufe ich diese sbrk() auf? Ich arbeite unter OSX und mit dem Qt-Creator, als Compiler nutze ich das eingebaute Clang von OSX.
Wie sieht es mit den Füllbyte beim Anlegen einer Struktur im Stack aus?
-
delcare schrieb:
Wie sieht es mit den Füllbyte beim Anlegen einer Struktur im Stack aus?
sizeof ist sizeof. völlig egal ob das objekt auf dem stack oder heap liegt, die paddingbytes sind identisch.
-
Naja, ich frage nur weil sizeof ja nicht für die Reservierung auf dem Stack benutzt wird, da ja hier die Definition alles erledigt. Oder liege ich da falsch?
-
delcare schrieb:
Wie sieht es mit den Füllbyte beim Anlegen einer Struktur im Stack aus?
Die Füllbytes werden so angelegt, dass der Prozessor schnell an die einzelnen Elemente kommt. D.h. nach Möglichkeit mit einem Speicherzugriff.
Ebenso berücksichtigt der Compiler die Füllbytes am Ende, damit der Zugriff bei Arrays ebenso schnell geht.
Das Stichwort dazu ist Alignment
-
Kann es also passieren, dass wenn ich ein Array von 100Bytes reserviere, es am Ende gar 256 Byte werden, da dann hier per 16Bit-Word darauf zugegriffen werden kann und die auch ein schönes zusammenhängender Block ist?
Warum steht so etwas nicht in in den vielen Büchern und Tuts über C?
-
declare schrieb:
Kann es also passieren, dass wenn ich ein Array von 100Bytes reserviere, es am Ende gar 256 Byte werden, da dann hier per 16Bit-Word darauf zugegriffen werden kann und die auch ein schönes zusammenhängender Block ist?
Warum steht so etwas nicht in in den vielen Büchern und Tuts über C?
Es gibt in Sachen Ausrichtung ziemlich strenge Systeme.
Die zwingen einen, dass int (32bit) Werte zum Beispiel nur an Adressen liegen, die durch 4 teilbar sind (also ptr%4==0).Jetzt schau dir diese Struktur an - und stell dir vor, der Compiler würde hier nicht Padding einfügen:
struct test { int a; // 0 char b; // 4 int c; // 5 <-- datatype misalignment!!! };
Wenn jedes Element so im Speicher abgelegt wird, wie hier angegeben, so gibts Probleme wenn man auf c zugreift.
Manche Prozessoren wie x86 mögen da verzeihend sein, andere wie MIPS werfen eine Exception vom Typ datatype misalignment.Was tun? Einfach ein Padding einfügen (der Compiler macht das für dich)!
struct test { int a; // 0 char b; // 4 char padd1; char padd2; char padd3; int c; // 8 <-- ist ok weil 8%4==0 };
Es macht also Sinn, wenn man sich ein bisschen Gedanken macht wie man die Daten in Strukturen anordnet.
struct test { int a; int b; int c; char d; char e; // +2byte padding };
ist besser wie
struct test { char d; // +3byte padding int a; int b; char e; // +3byte padding int c; };
-
noch ein kleiner Test mit dem MS Compiler:
//------------------------------ struct StrA { int a; // 4 byte char b; //1 byte // +3 byte int c; // 4 byte char d; // 1 byte // +3 byte // ========= // 16 byte }; //------------------------------ struct StrB { int a; // 4 byte int c; // 4 byte char b; // 1 byte char d; // 1 byte // +2 byte }; //------------------------------ int main(int,char**) { printf("A=%d B=%d",sizeof(StrA),sizeof(StrB)); // ... }
Output: A=16 B=12
-
Besten Dank, für das sehr anschauliche Beispiel.