Hallo, ich habe eine Struktur foo in einem .c-File erstellt und eine entsprechende Variable bar definiert: struct foo {int a; int b;}; ... struct foo bar; Nun möchte ich bar in einem Header-File extern deklarieren. Genügt es, zu schreiben: extern struct foo bar; ? Der Compiler bringt zumindest keinen Fehler. Oder sollte der Compiler den Aufbau der Struktur wissen, so dass ich die Typdefinition auch noch in die externe Deklaration mit hinein nehmen muss? Ich weiß dass es besser wäre, die Typdefinition in das Header-File zu schreiben und im C-File nur die Variable zu definieren, aber das ist aufgrund des Anwendungsfalls nicht möglich.
Nixwisser wrote: > Genügt es, zu schreiben: > > extern struct foo bar; ? > > Der Compiler bringt zumindest keinen Fehler. > > Oder sollte der Compiler den Aufbau der Struktur wissen, so dass ich die > Typdefinition auch noch in die externe Deklaration mit hinein nehmen > muss? Das hängt davon ab, was du damit hernach anstellen willst. Vom logischen Standpunkt: solange der Compiler keinen Speicher für bar außerhalb anlegen muss und solange er nicht auf dessen Elemente zugreifen muss, geht das. In C-Standardsprache gefasst heißt das, du hast eine unvollständige Typdeklaration für struct foo. Letztlich beschränkt sich dadurch das, was du mit dem Objekt bar anstellen kannst darauf, dass du dessen Adresse bilden kannst und diese bspw. an eine Funktion weiterreichen oder mit einem Zeiger (der auf eine Element vom Typ struct foo zeigt) auf Gleichheit testen.
Auf die Elemente von bar wird aber zugegriffen, und zwar bevor bar definiert wird. Warum gibt der Compiler dann keine Fehlermeldung aus? Die Übersetzungseinheit würde nach Inkludierung so aussehen: extern struct foo bar; (aus h-File) ... struct foo {int a; int b}; (c-File) ... bar.a = 1; (c-File) bar wird in einem anderen c-File definiert. Ist der Compiler so schlau, die Typdefinition von struct foo nachträglich mit der externen Deklaration von bar im Header zu verbinden?
Nixwisser wrote: > Ist der Compiler so schlau, die Typdefinition von struct foo > nachträglich mit der externen Deklaration von bar im Header zu > verbinden? Ist ja nicht "nachträglich": er hat die Definition des Typs gesehen, bevor er das erste Mal auf ein Element von bar zugreifen musste. Damit ist alles in Butter, er hat zu diesem Zeitpunkt die notwendigen Informationen beisammen gehabt.
Nein, in diesem Falle wird die externe Deklaration mit der darauffolgenden überschrieben. struct foo {int a; int b}; gehört nicht in ein C-File, sondern in eine Headerdatei. Und zwar vor die Deklaration extern struct foo bar;
>Ist ja nicht "nachträglich": er hat die Definition des Typs gesehen, >bevor er das erste Mal auf ein Element von bar zugreifen musste. >Damit ist alles in Butter, er hat zu diesem Zeitpunkt die notwendigen >Informationen beisammen gehabt. Das ist schon richtig, aber er die Variable wurde extern deklariert, bevor der angegebene Typ "struct foo" definiert wurde. Ist das kein Problem? >Nein, in diesem Falle wird die externe Deklaration mit der >darauffolgenden überschrieben. Also der Compiler legt sich in seinen Tabellen eine externe Variable bar vom Typ struct foo ab, und struct foo wird dann durch struct foo{int a; int b;} überschrieben? >struct foo {int a; int b}; > >gehört nicht in ein C-File, sondern in eine Headerdatei. >Und zwar vor die Deklaration Wie ich schon geschrieben habe, ist das nicht möglich (an dem c-File darf ich nicht drehen, nur Code "drumherum" bauen)
> Wie ich schon geschrieben habe, ist das nicht möglich (an dem c-File > darf ich nicht drehen, nur Code "drumherum" bauen) Dann musst Du pfuschen. Und die Deklaration des Strukturtyps trotzdem in die Headerdatei packen. Denn da gehört sie hin; wenn der Vollpfosten, der die C-Datei verbrochen hat, den Strukturtyp lokal definiert und trotzdem externen Zugriff darauf haben möchte, dann sollte er solange mit Ausgaben des K&R beworfen werden, bis er's einsieht.
>Dann musst Du pfuschen. Und die Deklaration des Strukturtyps trotzdem >in die Headerdatei packen. Meldet der Compiler dann nicht eine Typ-Neudefinition?
Nixwisser wrote: > Das ist schon richtig, aber er die Variable wurde extern deklariert, > bevor der angegebene Typ "struct foo" definiert wurde. Ist das kein > Problem? Deklarationen sind Schall und Rauch. ;-) Formal ist das Ding halt erst einmal mit einem unvollständigen Struturtyp deklariert. Das ist aber trotzdem eine gültige Deklaration, da man ja vom entsprechenden Objekt ggf. eine Adresse ermitteln kann (die dann auf den Typ struct foo zeigt, dessen Details dem Compiler nicht bekannt sein müssen). Wenn der Strukturtyp dann selbst noch deklariert wird, besitzt der Compiler die notwendige komplette Deklaration, um auch auf die Elemente von bar zugreifen zu können. Zwar unüblich aber legal. > Also der Compiler legt sich in seinen Tabellen eine externe Variable bar > vom Typ struct foo ab, Er merkt sich erstmal nur, dass er sie gesehen hat, dass es eine struct-Variable ist, aber dass der Typ unvollständig ist, sodass sie nur eingeschränkt benutzbar ist. > und struct foo wird dann durch struct foo{int a; > int b;} > überschrieben? Nicht ,überschrieben', sondern ,vervollständigt'.
Verstehe, danke. Ich hatte es zuvor mit einem typedef auf den Strukturtyp versucht. Diesen konnte ich der extern Deklaration aber nicht verwenden. Ich nehme mal an, dass liegt daran dass der Typ dem Compiler beim parsen der extern Deklaration nicht bekannt ist (die Typendefinition kommt ja erst später im c-File). Er braucht also zumindest einen "halben" Typ? ;)
Nixwisser wrote:
> Er braucht also zumindest einen "halben" Typ? ;)
Ja, er muss wissen, dass es eine struct ist und braucht den Namen der
struct auch noch, um sie ggf. zuordnen zu können. Durch diese
Möglichkeit lassen sich bspw. gegenseitig referenzierende Listen
implementieren:
1 | struct foo; |
2 | struct bar; |
3 | |
4 | struct foo { |
5 | struct bar *barp; |
6 | int foodata; |
7 | };
|
8 | |
9 | struct bar { |
10 | struct foo *foop; |
11 | int bardata; |
12 | };
|
Zu dem Zeitpunkt, da von struct bar ein Zeiger benutzt werden soll, ist über sie noch nichts weiter bekannt als ihr Name, aber das genügt für den Zweck.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.