www.mikrocontroller.net

Forum: Compiler & IDEs Globale Variablen, mehrere Dateien


Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
int GlobaleVar1;
int GlobaleVar2;

void foo()
{
  GlobaleVar1 = 5;
  GlobaleVar2 = 8;
}

und in allen anderen *.c nur diejenigen Globalen Variablen
zu deklarieren, die tatsächlich gebraucht werden:
extern int GlobaleVar2;

void bar()
{
  GlobaleVar2 = 9;
}

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

globale.h
*********
#ifndef EXTERN
#define EXTERN extern
#endif

EXTERN int GlobaleVar1;
EXTERN int GlobaleVar2;

... und die dann includieren ...

main.c
******
//
// durch den #define expandiert das Makro EXTERN in globale.h zu
// einem Leerstring. Dadurch wird aus
// EXTERN int a;
// die Zeile
// int a;
// und das definiert die Variable a
//
#define EXTERN
#include "globale.h"

int main()
{
}

a.c
***
//
// Hier gibt es keinen #define
// Dadurch definiert sich globale.h selbst ein Makro für EXTERN
// welches EXTERN durch 'extern' ersetzt. Aus
// EXTERN int a;
// wird daher
// extern int a;
// und das deklariert die Variable a ohne sie zu definieren
//
#include "globale.h"

void foo()
{
  GlobaleVar1 = 5;
  GlobaleVar2 = 8;
}

b.c
***
#include "globale.h"

void bar()
{
  GlobaleVar2 = 9;
}

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.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

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

Also ist der Gebrauch von "EXTERN" durchaus ratsam.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
extern int i;
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
extern int i;
extern int i;
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.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das widerspricht aber dann der Aussage von Rufus, meine Herren ;)

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Laut Rufus schon ;)

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Felix (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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 #4576815 wurde von einem Moderator gelöscht.
Beitrag #4576867 wurde von einem Moderator gelöscht.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.