Forum: Compiler & IDEs Globale Variablen, mehrere Dateien


von TechInfo (Gast)


Lesenswert?

Ich schon wieder.

Wenn ich ein Programm in mehrere .c-Files aufgespalten und globale 
Variablen deklariert habe, auf die mehrere Dateien zugreifen müssen, 
habe ich bis jetzt immer eine globals.h geschrieben, die dann in allen 
Files eingebunden wird. Bin aber grade ins Grübeln gekommen: Ist das die 
sinnvollste Möglichkeit?

von Karl H. (kbuchegg)


Lesenswert?

TechInfo wrote:
> Ich schon wieder.
>
> Wenn ich ein Programm in mehrere .c-Files aufgespalten und globale
> Variablen deklariert habe, auf die mehrere Dateien zugreifen müssen,
> habe ich bis jetzt immer eine globals.h geschrieben, die dann in allen
> Files eingebunden wird. Bin aber grade ins Grübeln gekommen: Ist das die
> sinnvollste Möglichkeit?

Ja.

Die Alternative ist, die globalen in ihrer jeweilgen
*.c zu definieren
1
int GlobaleVar1;
2
int GlobaleVar2;
3
4
void foo()
5
{
6
  GlobaleVar1 = 5;
7
  GlobaleVar2 = 8;
8
}

und in allen anderen *.c nur diejenigen Globalen Variablen
zu deklarieren, die tatsächlich gebraucht werden:
1
extern int GlobaleVar2;
2
3
void bar()
4
{
5
  GlobaleVar2 = 9;
6
}

auf lange Sicht zeigt sich aber, dass sowas in Chaos ausartet.
Alle Globalen in einem Header sammeln, ...

globale.h
*********
1
#ifndef EXTERN
2
#define EXTERN extern
3
#endif
4
5
EXTERN int GlobaleVar1;
6
EXTERN int GlobaleVar2;

... und die dann includieren ...

main.c
******
1
//
2
// durch den #define expandiert das Makro EXTERN in globale.h zu
3
// einem Leerstring. Dadurch wird aus
4
// EXTERN int a;
5
// die Zeile
6
// int a;
7
// und das definiert die Variable a
8
//
9
#define EXTERN
10
#include "globale.h"
11
12
int main()
13
{
14
}

a.c
***
1
//
2
// Hier gibt es keinen #define
3
// Dadurch definiert sich globale.h selbst ein Makro für EXTERN
4
// welches EXTERN durch 'extern' ersetzt. Aus
5
// EXTERN int a;
6
// wird daher
7
// extern int a;
8
// und das deklariert die Variable a ohne sie zu definieren
9
//
10
#include "globale.h"
11
12
void foo()
13
{
14
  GlobaleVar1 = 5;
15
  GlobaleVar2 = 8;
16
}

b.c
***
1
#include "globale.h"
2
3
void bar()
4
{
5
  GlobaleVar2 = 9;
6
}

ist auf lange Sicht die deutlich wartungsfreundlichere Lösung.
Dabei kann es durchaus sein, dass man für globale Variablen
mehrere Header Files macht, in denen die Globalen nach Themenkreisen
aufgeteilt sind. Das Prinzip ist aber dasselbe.

von TechInfo (Gast)


Lesenswert?

Braucht es denn diesen Makro unbedingt?

Kann man nicht in die Header-Datei

extern int GlobaleVariable

schreiben, die Header-Datei dann in jede .c einbinden und in einer 
.c-Datei dann noch zusätzlich die Definition

int GlobaleVariable

schreiben?

Oder beißen sich dann die Deklaration aus der Header-Datei und dei 
Definition aus der .c?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Genau, die extern-Deklaration und die "nicht-extern" Definition der 
Variablen beißen sich.

Also ist der Gebrauch von "EXTERN" durchaus ratsam.

von TechInfo (Gast)


Lesenswert?

Aber hier Beitrag "Problem mit globaler Variable" schreibst du, dass 
er in die Header-Datei die Variable mit extern deklarieren soll, und 
dann in einer .c die Variable definieren. Da die Header-Datei aber in 
beide files eingebunden wird, müßte es sich da doch auch beißen, oder?

von Karl H. (kbuchegg)


Lesenswert?

TechInfo wrote:
> Braucht es denn diesen Makro unbedingt?

Brauchen tut man das EXTERN Makro nicht unbedingt.

>
> Kann man nicht in die Header-Datei
>
> extern int GlobaleVariable
>
> schreiben, die Header-Datei dann in jede .c einbinden und in einer
> .c-Datei dann noch zusätzlich die Definition
>
> int GlobaleVariable
>
> schreiben?

Sicher kannst du.
Nur tippst du dann jede Variable 2 mal:

Einmal wenn du sie ins Header File einfügst. Das zweite
mal, wenn du sie dann in das eine bewusste *.c File
einfügst. Es soll schon vorgekommen sein, dass man beim
Tippen von ein und demselben Variablennamen Tippfehler
macht :-)

>
> Oder beißen sich dann die Deklaration aus der Header-Datei und dei
> Definition aus der .c?

Nein.
Im Endeffekt macht ja das Makro auch nichts anderes.
Mit dem EXTERN hab ich einfach nur einen Mechanismus, dass
ich beim includen in viele Files ein 'extern' davor kriege
und nur bei einem einzigen File wird das 'extern' unterdrückt.
Ist doch (fast) perfekt.

Fast perfekt deshalb, weil das ganze bei Initialisierungen
nicht mehr greift:
Ist bei einer Variablendekleration

  extern int i = 0;

eine Initialisierung angegeben, dann wird das extern leider
ignoriert. Andersrum wärs mir lieber, ist aber so.

von Karl H. (kbuchegg)


Lesenswert?

> Oder beißen sich dann die Deklaration aus der Header-Datei und dei
> Definition aus der .c?

Um das nochmal aufzugreifen:

Du kannst von einem Ding beliebig viele Deklerationen haben,
solange die Deklerationen immer das gleiche aussagen.
1
extern int i;
2
extern int i;

ist perfektes C.
Sieh es so: Eine derartige Dekleration kann umgangssprachlich
gelesen werden als:

Es gibt irgendwo eine Variable i. Wo es die gibt, braucht dich
jetzt nicht zu kümmern. Nimm einfach zur Kenntnis, dass sie
da ist und das daher in weiterer Folge die Verwendung von i
kein Syntaxfehler ist. Ach ja. Die Variable i ist vom Typ int.

Wenn der Compiler zum ersten mal auf diese Dekleration stöst,
dann trägt er in seine internen Tabellen ein: i existier, ist
vom Typ int.
Wenn der Compiler zum zweiten mal auf diese Dekleration stöst,
dann merkt er aufgrund seiner internen Tabellen: "Weis ich schon"
und macht nichts.

Wenn du schreibst
1
extern int i;
2
extern int i;
3
int i;

dann läuft bei den ersten beiden Deklerationen genau dasselbe
ab. Dann kommt die Definition und der Compiler wird zusätzlich
auch noch angehalten diese Variable jetzt auch tatsächlich
zu erzeugen. Da aber die Deklerationen und die Definitionen
übereinstimmen (in allen Fällen lautet die Aussage: ist vom Typ int)
hat der Compiler keinen Grund, da rumzumäkeln.

von TechInfo (Gast)


Lesenswert?

Das widerspricht aber dann der Aussage von Rufus, meine Herren ;)

von TechInfo (Gast)


Lesenswert?

>> Oder beißen sich dann die Deklaration aus der Header-Datei und dei
>> Definition aus der .c?
>
>Nein.
>Im Endeffekt macht ja das Makro auch nichts anderes.
>Mit dem EXTERN hab ich einfach nur einen Mechanismus, dass
>ich beim includen in viele Files ein 'extern' davor kriege
>und nur bei einem einzigen File wird das 'extern' unterdrückt.
>Ist doch (fast) perfekt.

Das Makro macht schon etwas anderes. Ohne das Makro wird in EINER 
.c-Datei, nämlich in der wo die Variable definiert wird, nach Auflösung 
der include-Anweisung stehen:

extern int var;
int var;

Durch das Makro wird in besagter Datei dann nur stehen:

int var;

von Karl H. (kbuchegg)


Lesenswert?

TechInfo wrote:

> Das Makro macht schon etwas anderes. Ohne das Makro wird in EINER
> .c-Datei, nämlich in der wo die Variable definiert wird, nach Auflösung
> der include-Anweisung stehen:
>
> extern int var;
> int var;
>
> Durch das Makro wird in besagter Datei dann nur stehen:
>
> int var;

Das macht aber logisch gesehen keinen Unterschied.

von TechInfo (Gast)


Lesenswert?

Laut Rufus schon ;)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Gerade kürzlich hatte ich mit 'nem Compiler zu tun, der tatsächlich 
motzte, wenn eine Variable sowohl extern als auch nicht-extern 
deklariert wurde - aber das scheint glücklicherweise die Ausnahme zu 
sein. Naja, MS halt.

von Felix (Gast)


Lesenswert?

Hi

Sehr gut, wie ihr das hier mit extern erklärt habt. Klingt auch alles 
sehr logisch. Nur ich mache das immer ohne "extern" und es funzt auch. 
Soll heißen: Die Headerdatei mit der Definition z.B.

volatile uint8_t var;

wird in jede Datei eingebunden, in der die Variable var benötigt wird. 
Und das klappt.

Ist das aus irgendwelchen Günden schlecht? Oder passiert da sogar 
irgendwas, was ich zwar nicht bemerke, was mir aber trotzdem Probleme 
bereiten könnte?

VG
felix

von Karl H. (kbuchegg)


Lesenswert?

Felix wrote:
> Hi
>
> Sehr gut, wie ihr das hier mit extern erklärt habt. Klingt auch alles
> sehr logisch. Nur ich mache das immer ohne "extern" und es funzt auch.
> Soll heißen: Die Headerdatei mit der Definition z.B.
>
> volatile uint8_t var;
>
> wird in jede Datei eingebunden, in der die Variable var benötigt wird.
> Und das klappt.

Das klappt weil dein Compiler/Linker eine Erweiterung mit
haben, die eine derartige 'multiple definition' unterstützt.

Wenn man pingelig ist, könnte man sagen du programmierst in
irgendeiner Sprache, die zwar fast wie C aussieht aber nicht
C sein kann. Denn in C ist sowas verboten :-)

PS: Der gcc kann das auch. Trotzdem mache ich das nicht. Das
extern kostet mir nichts und ich bin zumindest an dieser Stelle
C-konform.

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


Lesenswert?

Karl heinz Buchegger wrote:

> Sicher kannst du.
> Nur tippst du dann jede Variable 2 mal:

> Einmal wenn du sie ins Header File einfügst. Das zweite
> mal, wenn du sie dann in das eine bewusste *.c File
> einfügst.

Dann denkt man aber einmal mehr drüber nach, ob man wirklich eine
externe Variable braucht. ;-)

> Es soll schon vorgekommen sein, dass man beim
> Tippen von ein und demselben Variablennamen Tippfehler
> macht :-)

Dafür können Editoren aber seit 20 Jahren copy&paste, nicht?

> Wenn man pingelig ist, könnte man sagen du programmierst in
> irgendeiner Sprache, die zwar fast wie C aussieht aber nicht
> C sein kann. Denn in C ist sowas verboten :-)

Bist du dir da so sicher?  Das Überlagern gleichnamiger externer
Variablen in einem common block ist eine der ,,historisch
gewachsenen'' Implementierungsmöglichkeiten, die im Standard zumindest
irgendwo erwähnt war...

Ah nein, hab's gefunden.  Nicht im Standard, sondern im C99 Rationale,
Punkt 6.2.2. ``Linkages of identifiers''.  Dort werden Programme, die
nach sich auf dieses Prinzip (Relaxed Ref/Def) verlassen beschrieben
als:

`` ... UNIX C programs which take advantage of this model are standard
conforming in their environment, but are not maximally portable (not
strictly conforming).''

Beitrag #5239059 wurde von einem Moderator gelöscht.
Beitrag #5239109 wurde von einem Moderator gelöscht.
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.