Forum: Mikrocontroller und Digitale Elektronik Bitte um Verständnishilfe bei einem externen struct


von Fred (Gast)


Lesenswert?

Mal eine Fage zu externen structs.

Ich habe eine Header-Datei, in der ein struct definiert wird.
1
// variablen.h
2
3
stuct xyz
4
{
5
  ...
6
  ...
7
  ...
8
};
9
10
static struct abc xyz = { ..., ..., ..., ... };

Jetzt habe ich mehrere Funktionen, die da drauf zugreifen sollen, also 
binde ich diese variablen.h in jede der c-Funktionen ein
1
// datei_a.c
2
3
#include "variablen.h"
4
5
...
1
// datei_b.c
2
3
#include "variablen.h"
4
5
...

Muss ich jetzt in den c-Dateien noch extra ein extern einfügen, oder 
reicht es, wenn die variablen.h so eingebunden ist? Funktionieren 
(Kompilieren) tut es so, aber der Korrektheit halber frage ich lieber 
nach.

Also als Alternative
1
// datei_a.c
2
3
#include "variablen.h"
4
5
extern struct abc;
6
7
...

von Peter II (Gast)


Lesenswert?

was willst du erreichen, ohne extern hast du in jeder C datei eine neue 
Variabel mit dem gleichem namen (jede braucht speicher).

Mit dem Extern gibt es nur eine Variable.

von U.R. Schmitt (Gast)


Lesenswert?

Man definiert in einer Header Datei nur die Datentypen und nicht 
tatsächliche Variablen!
Wenn du eine globale Variable brauchst, dann definiere die in einem .c 
Modul und mache eine extern Referenz in der dazugehörigen .h Datei. 
Diese .h Datei kannst du dann in den .c Modulen includieren, in denen du 
auf diese Variable zugreifen willst.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Fred schrieb:
> Ich habe eine Header-Datei, in der ein struct definiert wird.
> // variablen.h
>
> stuct xyz  // typo!
> {
>   ...
>   ...
>   ...
> };
>
> static struct abc xyz = { ..., ..., ..., ... };

Die Zeile enthält einen Fehler, weil Du Strukturtypnamen und 
Variablennamen vertauscht hast:

 static struct xyz abc = { ..., ..., ..., ... };


Die letzte Zeile hat in der Headerdatei nichts verloren, denn sie 
bewirkt etwas komplett anderes als Du erwartest.

Sie sorgt nämlich dafür, daß in jedem C-Modul, das diese Headerdatei 
einbindet, eine eigene Instanz der Strukturvariablen angelegt wird, 
auf die von anderen C-Modulen nicht zugegriffen werden kann.

Was Du erreichen möchtest, sieht so aus:
1
struct xyz
2
{
3
  ...
4
  ...
5
  ...
6
};
7
8
extern struct xyz abc;

Diese letzte Zeile deklariert die Variable "abc", d.h. sie teilt dem 
Compiler mit, daß sie existiert und welchen Typ sie hat, aber sie 
definiert sie nicht, d.h., der benötigte Speicher wird nicht 
reserviert und eine Initialisierung mit Werten fehlt.

Beides gehört in genau ein C-Modul und sieht dann so aus:
1
#include "variablen.h"
2
3
struct xyz abc = { ..., ..., ..., ... };

von Guru (Gast)


Lesenswert?

>Ich habe eine Header-Datei, in der ein struct definiert wird.
Das ist so nicht vollständig beschrieben.
Mit dem gezeigten Teilinhalt der Header-Datei
1
stuct xyz
2
{
3
  ...
4
  ...
5
  ...
6
};

 wird zunächst eine Struktur "deklariert", d.h. ihr Name und ihr 
Aussehen beschrieben, ohne das zunächst dafür Speicherplatz reserviert 
wird.

Mit dem in der gleichen Header-Datei folgenden Code
1
static struct abc xyz = { ..., ..., ..., ... };

wird bewirkt, das in jeder C Datei, die diese Header-Datei mittels 
include einfügt, Speicherplatz für eine statische Variable mit der oben 
beschriebenen Struktur reserviert wird. Das static bewirkt dabei, das 
diese Variable nur und ausschliesslich in dieser C-Datei sichtbar ist.
In Deinem Code wird also jeweils in dem Codebereich der Datei datei_a.c
und datei_b.c für eine solche Variable Speicherplatz reserviert.

Das für von Dir nachgefragte Codefragment
1
extern struct abc;
ist zunächst einmal syntaktisch unvollständig und wird eine 
Fehlermeldung bewirken, da Du zwar den Namen abc der Struktur nennst, 
aber nicht die Variable auf die Du hier mit extern verweist.

Selbst die zusätzliche Angabe von xyz, also der Variablen die static in 
dem Codeteil definiert ist, wird nicht helfen sondern wieder eine andere 
Fehlermeldung provozieren, weil in dem Codeabschnitt sowohl eine 
statische Variabel namens xyz vorhanden ist als auch auf eine externe 
Variable gleichen Namens verwiesen wird. Bei der Verwendung von xyz kann 
der Compiler nicht unterscheiden ob Du die lokale, statische Variable 
meinst oder die externe.

Der "normale" Weg ist, in Header-Dateien überhaupt keinen Speicherplatz 
für Variablen zu reservieren. (Allenfalls, aber das ist dann schon einen 
Schritt weiter kann etwa über den Präprozessor eine Unterscheidung 
zwischen einer "Hauptdatei", die also "hauptsächlich" diese Variable 
manipuliert und "Nebendateien" die diese Variablen nur selten brauchen, 
gemacht werden). Folgt man dem einfachsten Weg, ist schon die Benennung 
der Header-Datei mit variablen.h unkorrekt, da in solchen Header-Dateien 
kein Speicherplatz reserviert wird.

Die Codeabschnitte würden also vielmehr so aussehen müssen.
1
// structures.h
2
stuct xyz
3
{
4
  ...
5
  ...
6
  ...
7
};

und

1
// datei_a.c
2
3
#include "structures.h"
4
struct abc xyz = { ..., ..., ..., ... }; // hier wird speicherplatz reserviert
5
...

und
1
// datei_b.c
2
3
#include "variablen.h"
4
extern struct abc xyz;   // hier wird auf den schon in Datei_a reservierten Speicherplatz verwiesen
5
...

Das solltest Du erstmal so machen. Lies auch bitte die Abschnitte über 
die Schlüsselworte static und extern sowie über die Sichtbarkeitsregeln 
in einem C Buch Deiner Wahl.

von Guru (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:

>Die Zeile enthält einen Fehler, weil Du Strukturtypnamen und
>Variablennamen vertauscht hast:

Oops. Ja richtig. Das habe ich übersehen. Musst Du also entsprechend 
ändern.
Und der angemerkte syntaktische Fehler ist vielmehr das Du an der Stelle 
des Strukturnamens den Variablennamen genannt hast, der Strukturname 
aber fehlt.

von Fred (Gast)


Lesenswert?

So, bin wieder da! Sorry, musste eben was erledigen!

Also besten Dank schonmal für die Antworten - jetzt wird es mir klar. 
Der Compiler meckert also nicht, weil es völlig OK ist, überall ein 
neues "gleiches" struct anzulegen.

Ich werde nun also folgendes tun:
1
// structs.h
2
3
struct abc
4
{
5
  ...
6
  ...
7
};
8
9
extern struct abc xyz;
1
// struct.c
2
3
#include "structs.h"
4
5
static struct abc xyz = { ..., ... };

Und dann in den jeweiligen .c-Dateien
1
// datei_a.c
2
3
#include "structs.h"
4
5
extern struct abc xyz;

Ist das dann so richtig? Oben war abc und xyz vertauscht, das stimmt.
Wie verhält es sich mit dem static hier? Was static generell bewirkt, 
ist mir klar, aber hier kann ich grad nicht einschätzen, ob nötig oder 
nicht.

Ich würde sagen ja!

von U.R. Schmitt (Gast)


Lesenswert?

Besser aber noch nicht ganz richtig.
Da in deiner Datei struct.h schon die Zeile:
extern struct abc xyz;
drin ist, musst du das in den C Dateien, in denen du die globale 
Variable xyz benutzen willst nicht nochmal extra schreiben.

p.s. Man benutzt nicht Schlüsselworte der Sprache für Variablen oder 
Dateinamen. Nenn die .c und .h Datei so daß klar wird wofür das Modul 
ist, aber nicht struct.c bzw. struct.h.

von Fred (Gast)


Lesenswert?

Nein, Quark...die Struktur pack ich auch noch in structs.c

von Fred (Gast)


Lesenswert?

U.R. Schmitt schrieb:
> Da in deiner Datei struct.h schon die Zeile:
> extern struct abc xyz;

Stimmt, klar! Brauche ich ja dann nurnoch inkludieren. OK, jetzt hab 
ichs gerafft. Aber die Struktur selbst kann auch in die .c, oder? Und in 
der .h dann nurnoch die extern struct ...

U.R. Schmitt schrieb:
> p.s. Man benutzt nicht Schlüsselworte der Sprache für Variablen oder
> Dateinamen. Nenn die .c und .h Datei so daß klar wird wofür das Modul
> ist, aber nicht struct.c bzw. struct.h.

Ja, hab ich auch nicht, die heißen anders, war jetzt nur als Beispiel

von U.R. Schmitt (Gast)


Lesenswert?

Vergessen: Hmm, ich habe wohl schon zu lange nicht mehr c programmiert. 
static schränkt doch die Sichtbarkeit der Variable nach aussen hin ein. 
Insofern bin ich jetzt nicht sicher ob das so Sinn macht oder gar zu 
Fehlern/Warnings beim Linken führen kann.
Da müssen die Jungs die täglich C programmieren noch mal ran, ich bin 
etwas eingerostet und habe hier keinen C-Compiler.

von Fred (Gast)


Lesenswert?

U.R. Schmitt schrieb:
> static schränkt doch die Sichtbarkeit der Variable nach aussen hin ein.

Naja in erster Linie sorgt es doch dafür, dass der Speicher nicht wieder 
freigegeben wird und mir der Inhalt der Variable erhalten bleibt.

von U.R. Schmitt (Gast)


Lesenswert?

Fred schrieb:
> Stimmt, klar! Brauche ich ja dann nurnoch inkludieren. OK, jetzt hab
> ichs gerafft. Aber die Struktur selbst kann auch in die .c, oder? Und in
> der .h dann nurnoch die extern struct ...

Nein, die deklaration
struct abc
{
  ...
  ...
};

extern struct abc xyz;
soll ja im .h File sein, damit jeder der das Teil benutzen will weiß wie 
die Variable xyz aufgebaut ist.

So wie Rufus es schon am Anfang geschrieben hat ist es korrekt.
In den Modulen in denen zu auf xyz zugreifen willst musst du nur die .h 
datei includieren.

von U.R. Schmitt (Gast)


Lesenswert?

Fred schrieb:
> Naja in erster Linie sorgt es doch dafür, dass der Speicher nicht wieder
> freigegeben wird und mir der Inhalt der Variable erhalten bleibt.

Das ist kein Java. static hat in c eine völlig andere Bedeutung. Sobald 
die Variable in C ausserhalb einer Funktion deklariert ist, ist sie 
global und damit solange gültig wie das Programm läuft.

von Fred (Gast)


Lesenswert?

U.R. Schmitt schrieb:
> Nein, die deklaration
> struct abc
> {
>   ...
>   ...
> };
>
> extern struct abc xyz;
> soll ja im .h File sein

Ja, anders funktioniert es auch nicht.

von U.R. Schmitt (Gast)


Lesenswert?

Übrigens solltest du dir Gedanken machen ob du diese globale Variable 
überhaupt global brauchst, oder ob es nicht sinnvoller ist sie dort 
anzulegen wo sie gebraucht wird und den aufgerufenen Funktionen einen 
Zeiger auf die Variable mitzugeben.
Globale variablen werden oft und gerne von Anfängern benutzt und führen 
schnell zu völlig unmodularem Spagetticode.
Echt notwendige globale Variablen sind vergleichsweise selten.
Wobei die Gewichtung für kleine µC Programme mit wenig Speicher etwas 
anders ist.

von Fred (Gast)


Lesenswert?

Ok Leute, sorry, aber jetzt muss ich doch nochmal das "static" 
aufgreifen...

Ich habe jetzt grad echt versucht, das Problem hier mittels Buch zu 
lösen, aber ich raff es nicht.

Ich habe jetzt Strukturtyp in der .h
Dann extern auf eine Struktur diesen Typs

In der .c eine Variable mit der Struktur


Wenn ich diese Variablen als static struct ... deklariere, dann gibt es 
Fehler. Kann mir das einer erklären?

Doch was mit der Sichtbarkeit?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Fred schrieb:
> Wie verhält es sich mit dem static hier? Was static generell bewirkt,
> ist mir klar, aber hier kann ich grad nicht einschätzen, ob nötig oder
> nicht.

Nein, hier ist es explizit falsch. Das darf da nicht hin.

static hat in C zwei unterschiedliche Bedeutungen. Wird eine Variable 
innerhalb einer Funktion als static deklariert, so behält die 
Variable ihren Speicherinhalt auch zwischen zwei Funktionsaufrufen und 
eine etwaige Initialisierung erfolgt nur einmalig zum Programmstart.

Das scheint mir die Dir bekannte Funktionsweise zu sein, hier aber 
greift die andere:

Wird eine Variable aber außerhalb einer Funktion als static 
deklariert, so ist sie nur innerhalb des C-Moduls sichtbar, in der sie 
deklariert wird.
Ein Zugriff auf sie aus anderen C-Modulen ist nicht möglich.

Technisch bedeutet das, daß der Compiler in der zum Modul gehörenden 
Symboltabelle als static deklarierte Variablen (und auch Funktionen) 
nicht einträgt, so daß der Linker diese Symbolnamen bei Referenzierungen 
aus anderen Modulen nicht auflösen kann.

von Fred (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Wird eine Variable aber außerhalb einer Funktion als static
> deklariert, so ist sie nur innerhalb des C-Moduls sichtbar, in der sie
> deklariert wird.

Achso! Ja, das wusste ich echt nicht und habs grad auch nicht gefunden. 
Nun gut, dann ist meiner Variable ja eh global vor allen Funktionen 
deklariert, also bleibt der Inhalt.

OK, die Sache mit den Pointern werde ich nochmal überdenken. Aber 
erstmal bin ich froh, dass sich das geklärt hat.

Aber nur mal allgemein: Warum macht es Sinn, dass man Variablen oder 
Funktionen als static deklariert, damit sie nur in der dazugehörigen 
.c-Datei verfügbar sind?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Fred schrieb:
> Aber nur mal allgemein: Warum macht es Sinn, dass man Variablen oder
> Funktionen als static deklariert, damit sie nur in der dazugehörigen
> .c-Datei verfügbar sind?

Der Sinn ist das "information hiding". Außerhalb eines Moduls ist nur 
dessen definierte Schnittstelle interessant, Implementierungsdetails 
sollen per Design nicht von außen sichtbar sein.

Davon abgesehen lassen sich so auch Namenskonflikte vermeiden.
Angenommen, in Modul A wird eine Variable kram_ist_initialisiert 
verwendet, aber in Modul B geschieht dasselbe. Je nach verwendetem 
Linker wird dann entweder ein mehrfach definiertes Symbol als 
Fehlermeldung ausgeworfen, ober aber alle derartigen Variablen werden zu 
einer zusammengefasst.

Letzteres dürfte kaum das Designziel der Ersteller von Modul A und Modul 
B sein.

von Fred (Gast)


Lesenswert?

Ich danke euch für die vielen Infos!

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.