Uninitialisiertes Array in eigenem Struct mit unbestimmter Grösse.
-
Hi all,
mal ne Frage zu meinem Struct:
typedef Mein_Struct { int size; char array[size]; /* ... */ } my_struct;
Das Struct ist zu beginn uninitialisiert, trotzdem compiliert das so nicht,
weil "size" undefiniert (weil uninitialisiert) ist.Meine (falsche) Annahme war, ich schreibe eine Prozedur set_size(int s), welches einen uninitialisierten Prototypen des Structs nimmt und dann einfach size setzt, somit auch die max. Stringgrösse vom array. Hier pseudo-Code, wie es gemeint ist:
void set_size(my_struct *m, int s) { m->size=s; } /* ... */ my_struct m; // leeres Mein_Struct set_size(&m, 32); /* XYZ */
Ich dachte ab der Markierung XYZ ist m->size=32 UND m->array 32 Elemente gross.
Das stimmt offenbar NICHT.
Also wie bekomme ich ein Struct, mit einem Array unbestimmter Grösse darin?
(bzw. zum Zeitpunkt der Definition des Structs ist die Grösse unbekannt, muss/soll später gesetzt werden über Prozeduren/Funktionen.)Oder ist die Frage an sich schon Käse?
(Kommt bei mir gerne mal vor, schliesslich habe ich das Programmieren mit anderen Sprachen gelernt...)
Wenn ja, bitte workaround beschreiben, wie man das in ANSI C i.d.R. so macht/löst.Danke wie immer im Voraus.
-
Du hast einen Fehler in der Struct-Definition gemacht.
typedef [b]struct[/b] { ... } mystruct;
... char array[size]; ...
kann man nur dann im einem Struct verwenden, wenn size zur Kompilierzeit
bekannt ist, so z.B.:#define SIZE 100 typedef struct { int size; char array[SIZE]; } mystruct;
Dies hat den Nachteil, dass du nur SIZE-viele Elemente in den Array speichern
kannst und dass immer Speicherplatz für SIZE-viele Elemente angelegt wird,
auch wenn du nur ein Element einfügst.Variabler kannst du das hier mit Pointern machen:
typedef struct { int size; char *array; } mystruct; mystruct *new_mystruct(int size) { mystruct *el = malloc(sizeof(*el)); el->size = size; if (size>0) el->array = malloc(size*sizeof(*(el->array))); else el->array = NULL; return el; }
Gruß mcr
-
Seit C99 gibt es flexible array members:
#include <stdlib.h> struct foo { size_t size; char fam[]; // muss letztes Element in Struct sein }; int main (int argc, char **argv) { struct foo *bar = malloc (sizeof *bar + argc); bar->size = argc; free (bar); return 0; }
-
Tim schrieb:
Seit C99 gibt es flexible array members:
#include <stdlib.h> struct foo { size_t size; char fam[]; // muss letztes Element in Struct sein }; int main (int argc, char **argv) { struct foo *bar = malloc (sizeof *bar + argc); bar->size = argc; free (bar); return 0; }
Meines Wissens nach ist im Standard nicht festgelegt, dass die Reihenfolge
der Members eines Structs vom Compiler nicht verändert werden darf.
Das würde bedeuten, dass fam nicht immer an letzter Stelle sein muss.
Ob sich das nun mit C99 und flexiblen array members geändert hat, weiß ich
nicht.
Bisher ist mir auch kein Compiler bekannt, der die Reihenfolge ändert.Dein Beispiel funktioniert so auch vor C99 (ausgenommen s.o.):
struct foo { int size; char fam[0]; }
Sobald du aber einen anderen Typ als char verwendest, funktioniert die
Allozierung nicht mehr. Dann müsste es so lauten:struct foo { int size; int fam[0]; } struct foo *bar = malloc(sizeof(*bar) + (size-1) * sizeof(*(bar->fam))); bar->size = size;
Der Hack, den sich Tim hier zu Hilfe macht:
C verhindert nicht den Zugriff auf Speicher (Elemente) über Arraygrenzen
hinaus.Mit malloc wird genügend Speicher alloziert, auf dem dann mit fam[i]
zugegriffen werden kann.Ein Beispiel:
Startadresse von bar: 0x00 (ich weiß, dass das keine gültige Adresse ist.) Dann beginnt das Array fam bei: 0x04 Ein Malloc mit size=4 reserviert 8 (sizeof(*bar)) + 3*4 (size-1 * sizeof(int)) also 20 bytes, die wie folgt verteilt sind: bar->size: 0x00 - 0x03 bar->fam: 0x04 - 0x13 bar->fam[0]: 0x04 - 0x07 bar->fam[1]: 0x08 - 0x0b bar->fam[2]: 0x0c - 0x0f bar->fam[3]: 0x10 - 0x13
Diese Vorgehensweise hat als einzigen Vorteil, dass der Speicher für einen
Pointer gespart wird und die Daten hintereinander im Speicher liegen.Welche Variante nun die bessere, oder sichere ist, bleib dem Programmierer
überlassen.Gruß mcr
EDIT:
aber bei allen Möglichkeiten wird das Array nicht automatisch angelegt,
sondern muss handisch mit malloc alloziert werden.
-
mcr schrieb:
Meines Wissens nach ist im Standard nicht festgelegt, dass die Reihenfolge
der Members eines Structs vom Compiler nicht verändert werden darf.
Das würde bedeuten, dass fam nicht immer an letzter Stelle sein muss.
Ob sich das nun mit C99 und flexiblen array members geändert hat, weiß ich
nicht.Ich sehe den Widerspruch nicht. Ein flexible array member muss das letze Element sein. Innendrin darf die Reihenfolge (das erste Element und das optionale fam) sicherlich durchgewürfelt werden.
mcr schrieb:
Dein Beispiel funktioniert so auch vor C99 (ausgenommen s.o.):
struct foo { int size; char fam[0]; }
Das ist zwar mit ein paar Compilern möglich (gcc z.B.), ist aber non-standard.
mcr schrieb:
Der Hack, den sich Tim hier zu Hilfe macht:
C verhindert nicht den Zugriff auf Speicher (Elemente) über Arraygrenzen
hinaus.Ein Hack der so im Standard als Beispiel steht...
-
Tim schrieb:
Innendrin darf die Reihenfolge (das erste Element und das optionale fam) sicherlich durchgewürfelt werden.
werden sie nicht. struct members werden in der reihenfolge gespeichert, in der man sie hingeschrieben hat. irgendwie gab's, glaub ich, 'ne ausnahme bei bitfields.
-
~fricky schrieb:
Tim schrieb:
Innendrin darf die Reihenfolge (das erste Element und das optionale fam) sicherlich durchgewürfelt werden.
werden sie nicht. struct members werden in der reihenfolge gespeichert, in der man sie hingeschrieben hat. irgendwie gab's, glaub ich, 'ne ausnahme bei bitfields.
Tatsache. Ich weiss gar nicht wo ich das her hab
-
Tim schrieb:
Tatsache. Ich weiss gar nicht wo ich das her hab
Vielleicht von hier ?
Guckst du:
http://www.comeaucomputing.com/techtalk/c99/#flexiblearraysGruß,
B.B.
-
B.B. schrieb:
Tim schrieb:
Tatsache. Ich weiss gar nicht wo ich das her hab
Vielleicht von hier ?
Guckst du:
http://www.comeaucomputing.com/techtalk/c99/#flexiblearraysEs ging ja eher darum ob die Reihenfolge der Elemente eines struct die Reihenfolge der Deklaration einhalten müssen oder nicht. Oder verstehe ich dich falsch?
-
Ich dachte du wüsstest nicht mehr, woher du das Wissen um die letzte Position eines flexible array members hast.
Zur Reihenfolge der struct member sagt Committee Draft — May 6, 2005
6.7.2.1.
12 Each non-bit-field member of a structure or union object is aligned in an implementationdefined
manner appropriate to its type.
-
Das bezieht sich auf das alignment der Elemente (also wo padding bytes eingefügt werden), nicht auf die Reihenfolge der Elemente selbst.
-
Nagut, dann hab ich da wohl was mistverstanden.