Mal eine Fage zu externen structs.
Ich habe eine Header-Datei, in der ein struct definiert wird.
1
// variablen.h
2
3
stuctxyz
4
{
5
...
6
...
7
...
8
};
9
10
staticstructabcxyz={...,...,...,...};
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
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.
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.
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
structxyz
2
{
3
...
4
...
5
...
6
};
7
8
externstructxyzabc;
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:
>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
stuctxyz
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
staticstructabcxyz={...,...,...,...};
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
externstructabc;
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
stuctxyz
3
{
4
...
5
...
6
...
7
};
und
1
// datei_a.c
2
3
#include"structures.h"
4
structabcxyz={...,...,...,...};// hier wird speicherplatz reserviert
5
...
und
1
// datei_b.c
2
3
#include"variablen.h"
4
externstructabcxyz;// 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.
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.
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
structabc
4
{
5
...
6
...
7
};
8
9
externstructabcxyz;
1
// struct.c
2
3
#include"structs.h"
4
5
staticstructabcxyz={...,...};
Und dann in den jeweiligen .c-Dateien
1
// datei_a.c
2
3
#include"structs.h"
4
5
externstructabcxyz;
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!
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.
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
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.
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.
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.
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.
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.
Ü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.
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?
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.
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?
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.