Forum: Compiler & IDEs Struktur extern deklarieren


von Nixwisser (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Nixwisser (Gast)


Lesenswert?

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?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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;

von Nixwisser (Gast)


Lesenswert?

>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)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> 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.

von Nixwisser (Gast)


Lesenswert?

>Dann musst Du pfuschen. Und die Deklaration des Strukturtyps trotzdem
>in die Headerdatei packen.

Meldet der Compiler dann nicht eine Typ-Neudefinition?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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'.

von Nixwisser (Gast)


Lesenswert?

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? ;)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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
Noch kein Account? Hier anmelden.