Datum:
Hallo Ich möchte zwei structs definieren, die jeweils ein Pointer als Element enthalten um gegenseitig auf sich verweisen zu können. Also so:
typedef struct BOX { char *text; struct BOX_ITEM *boxItem; }; typedef struct BOX_ITEM { uint8_t value; struct BOX *box ; }; |
Dabei erhalte ich schon mal eine Warnung (jedoch nur beim 1. Compilieren, folgende Compilationen ohne Änderung des Codes bringen keine Warnungen mehr): ../box_test.c:29: warning: useless storage class specifier in empty declaration Weshalb gibts die Warnung nur beim ersten Mal? Wie kann ich nun je eine Instanz erzeugen, da
char mytext[] = "blabla"; // (1) struct BOX box1 = {mytext, &box1Item1}; // (2) struct BOX_ITEM box1Item1 = {0, &box1}; // (3) |
ein Fehler erzeugt, da der Compiler zum Zeitpunkt (2) box1item1 ja noch gar nicht kennt. Wie muss ich das Problem lösen? Was muss ich dazu in die header-Datei eintragen? Vielen Dank.
Datum:
Markus schrieb: > Dabei erhalte ich schon mal eine Warnung (jedoch nur beim 1. > Compilieren, folgende Compilationen ohne Änderung des Codes bringen > keine Warnungen mehr): > ../box_test.c:29: warning: useless storage class specifier in empty > declaration > Weshalb gibts die Warnung nur beim ersten Mal? Vermutlich wird die Datei nur beim ersten mal compiliert. Warum sollte das auch nochmal getan werden, wenn du die zwischendrin nicht änderst? > Wie muss ich das Problem lösen? Per "forward declaration": extern struct BOX_ITEM box1Item1; struct BOX box1 = {mytext, &box1Item1}; struct BOX_ITEM box1Item1 = {0, &box1}; > Was muss ich dazu in die header-Datei eintragen? Die extern-Deklaration.
Datum:
Markus schrieb: > typedef struct BOX { > char *text; > struct BOX_ITEM *boxItem; > }; > > typedef struct BOX_ITEM { > uint8_t value; > struct BOX *box ; > }; struct BOX { ... }; oder typedef struct { ... } BOX; Je nachdem ob man beim Anlegen von Variablen "struct BOX b;" oder einfach "BOX b;" schreiben will.
Datum:
Rolf Magnus schrieb: > Die extern-Deklaration. Warum um alles in der Welt extern? Sinple forward declaration reicht.
Datum:
ok danke, das klappt schon mal soweit. Doch weshalb brauche ich bei der Instanzierung noch das keyword struct bei
struct BOX_ITEM box1Item1 = {0, &box1}; // (3) |
? Ich mach ja bei der Definition ein typedef, deshalb sollte es doch auch ohne "struct" funktionieren?!? Falls ich es (sowohl im .c als auch im .h-File) weglasse, erscheint die Meldung: ../box_test.c:34: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'box1Item1' Wie kommt das?
Datum:
... ich hab soeben noch ein weiteres Problem: Wieso lässt sich der Wert eines Elements im struct nicht neuzuweisen?
char mytext[] = "blabla"; // (1) char secondtext[] = "blabla"; // (2) struct BOX box1 = {mytext, &box1Item1}; // (3) box1.text = second; // (4) |
Zeile 4 ruft folgenden Fehler hervor: ../box_test.c:39: error: expected '=', ',', ';', 'asm' or '__attribute__' before '.' token Was bedeutet das? Vielen Dank für eure Hilfe!
Datum:
In der Syntax von C gibt es dedizierte Positionen für die Namen von structs und von typedefs.
typedef struct <struct_name> {
blabla
} <typname>;
<typname> VarableX;
|
Du kannst auch structs deklarieren ohne deswegen einen neuen Typ zu definieren.
struct <struct_name> {
blabla
};
struct <struct_name> VariableX;
|
Du kannst auch den struct namen weglassen wenn Du einen Typen definierst. Eine sog. anonyme Struktur.
typedef struct {
blabla
} <typename>;
<typname> VariableX;
|
Aber was Du nicht kannst, ist den typnamen weglassen und stattdessen den struct-namen als Typnamen verwenden, wie Du es getan hast.
typedef struct <struct_name> {
blabla
};
<typname> VariableX; // geht nicht, weil kein name für den Typ angegeben
struct <struct-name> VariableY; // geht, weil der struct name dennoch bekannt ist.
|
Wobei ich bei dem letzten Code zumindest eine Warnung erwarten würde, denn typdefinitionen ohne Typnamen sind eigentlich sinnlos. Du kannst also tpynamen und struct namen nicht in der gleichen Weise verwenden. struct <struct-name> definiert eben keinen Typen. Deswegen musst Du ausdrücklich struct <struct-name> schreiben, wenn Du eine Variable mit der Struktur als ihrem Typ anlegen willst. Lies mal in einem C-Buch nach.
Datum:
In welchem Kontext steht denn Zeile 4? Zuweisungen sind nur innerhalb von Funktionen möglich.
Datum:
>...wenn Du eine Variable mit der Struktur als ihrem Typ anlegen willst.
Ist eigentlich nicht korrekt ausgedrückt.
Ein Strukturname identifiziert keinen Typ sondern eben eine Struktur.
Anders ausgedrückt kann man "struct" resp. "union" als ein Typ wie int
oder char ansehen, er bedarf aber eines Namens, eben der gewollten
"struct" oder "union" um an Stelle eines Typs stehen zu können, also ein
Typ "zu sein".
Datum:
Da Struct-Namen einen eigenen Namespace besitzen kann man "struct XXX" und einen Typedefname XXX auch kombinieren:
typedef struct BOX { char *text; struct BOX_ITEM *boxItem; // nicht: BOX_ITEM *boxItem; } BOX; typedef struct BOX_ITEM { uint8_t value; struct BOX *box ; // oder auch: BOX *box; } BOX_ITEM; |
Man kann dann überall dort die Form "struct XXX" verwenden, wo diese Struct noch nicht bekannt ist und hat dennoch die Möglichkeit, im Rest vom Code den Typedef-Name benutzen zu können. Mit dem gleichen Namen. Man kann alternativ auch den Typedef vorziehen und die Struct nachreichen:
typedef struct BOX_ITEM BOX_ITEM; typedef struct BOX BOX; struct BOX { char *text; pBOX_ITEM boxItem; }; struct BOX_ITEM { uint8_t value; pBOX box; }; |
Datum:
Oops, so wars gemeint:
typedef struct BOX_ITEM BOX_ITEM; typedef struct BOX BOX; struct BOX { char *text; BOX_ITEM *boxItem; }; struct BOX_ITEM { uint8_t value; BOX *box; }; |
oder kürzer
typedef struct BOX_ITEM BOX_ITEM; typedef struct BOX { char *text; BOX_ITEM *boxItem; } BOX; struct BOX_ITEM { uint8_t value; BOX *box; }; |
Datum:
Markus schrieb: > Weshalb gibts die Warnung nur beim ersten Mal? Weil das nur eine Warnung ist, und die c-Datei trotzdem kompiliert wurde. Da make nur geänderte Files neu kompiliert, bekommt der Compiler die Datei bei späteren build-Vorgängen gar nicht mehr zu sehen, damit gibt es da auch keine Warnung mehr. Willst du das nicht, hilft -WError. Dann wird jede Warnung als Fehler behandelt. Oliver
Datum:
XTerminator schrieb: > Rolf Magnus schrieb: >> Die extern-Deklaration. > > Warum um alles in der Welt extern? Sinple forward declaration reicht. Weil man bei globalen Variablen eine "simple forward declaration" macht, indem man extern davor schreibt. A. K. schrieb: > Man kann alternativ auch den Typedef vorziehen und die Struct > nachreichen: Aber auch nur weil
typedef struct BOX_ITEM BOX_ITEM; |
gleich noch eine implizite Deklaration von struct BOX_ITEM beinhaltet.
Datum:
Klar. Aber das ist die Vorzugslösung für Leute, die sich mit dem archaischen "struct XXX" aus grauer Vorzeit möglichst wenig befassen wollen. Man hat damit eine forward declaration vom typedef durchgeführt und kann bei den gewohnteren typedefs bleiben.
Datum:
Vielen Dank für die Inputs, hat mir sehr geholfen. LG Markus