Forum: PC-Programmierung verständnisproblem externe variable


von felix (Gast)


Lesenswert?

Hallo,

ich habe ein Verständnisproblem zu externen Variablen in C.
Warum muss ich extern davorschreiben?

nach: 
https://stackoverflow.com/questions/1433204/how-do-i-use-extern-to-share-variables-between-source-files


file3.h
1
extern int global_variable;  /* Declaration of the variable */

file1.c
1
#include "file3.h"  /* Declaration made available here */
2
#include "prog1.h"  /* Function declarations */
3
4
/* Variable defined here */
5
int global_variable = 37;    /* Definition checked against declaration */
6
7
int increment(void) { return global_variable++; }

file2.c
1
#include "file3.h"
2
#include "prog1.h"
3
#include <stdio.h>
4
5
void use_it(void)
6
{
7
    printf("Global variable: %d\n", global_variable++);
8
}

da ich aber doch file3.h eh inkludiere, ist die Variable doch bekannt?
Warum muss dann noch ein extern davor?

Oder ist es nur als bessere übersicht, dass global_variable nicht nur in 
file3.c benutzt wird?

von Dirk B. (dirkb2)


Lesenswert?

felix schrieb:
> da ich aber doch file3.h eh inkludiere, ist die Variable doch bekannt?
> Warum muss dann noch ein extern davor?

Mit extern ist es eine Deklaration. es wird dem Compiler bekannt gegebn, 
dass eine Variable mit dem Namen existiert.

Ohne extern ist es eine Definition.
Es wird eine Variable mit dem Namen angelegt.
Jede C-Datei, die diesen Header inkludiert, legt somit eine neue 
Variable an.
Und damit hat der Linker ein Problem.

von Wilhelm M. (wimalopaan)


Lesenswert?

Dirk B. schrieb:
> Jede C-Datei, die diesen Header inkludiert, legt somit eine neue
> Variable an.

Genau: deklarieren darf man sooft man will (sofern die Deklarationen 
gleich sind), definieren nur einmal. Das nennt sich ODR 
(one-definition-rule): man muss genau einmal ein Konstrukt definieren, 
nicht 0-mal und nicht >= 2-mal.

von Rolf M. (rmagnus)


Lesenswert?

felix schrieb:
> da ich aber doch file3.h eh inkludiere, ist die Variable doch bekannt?
> Warum muss dann noch ein extern davor?

Genau darum. Mit extern machst du die Variable nur bekannt. Das ist was 
anders, als sie zu erzeugen.

Mit
1
int global_variable = 37;    /* Definition checked against declaration */
sagst du dem Compiler: "Lege einen Integer mit Namen global_variable an, 
halte den Speicher dafür vor und schreibe den Wert 37 rein."
Mit
1
extern int global_variable;  /* Declaration of the variable */
sagst du ihm dagegen: "Ach, übrigens, es existiert eine Variable vom Typ 
int, und die heißt global_variable. Speicher ist dafür schon wo anders 
angelegt worden."

: Bearbeitet durch User
von Vudoh (Gast)


Lesenswert?

Das Schlüsselwort "extern" besagt schlicht und ergreifend nur, dass die 
Variable in einer anderen d.h. "externen" Datei definiert wird.
Deklaration = Typ und Namen der Variablen im Code angeben.
Definition = Der Variablen einen Wert verpassen.


Tipp:
Gehe sparsam mit solchen Variablen um, das kommt oft in Code vor der zu 
viele globale Variablen nutzt, globale Variablen sind zu vermeiden wenn 
es geht.

von Dirk B. (dirkb2)


Lesenswert?

Vudoh schrieb:
> Deklaration = Typ und Namen der Variablen im Code angeben.
> Definition = Der Variablen einen Wert verpassen.

Nein. Nein.

Deklaration = Typ und Name der Variablen werden „nur“ bekannt gegeben
Definition = Die Variable wird angelegt (in C ist das gleichzeitung noch 
eine Deklaration) Es wird Speicher verbraucht.
Initialisierung = erstmalige Wertzuweisung (bei der Definition)

von Vudoh (Gast)


Lesenswert?

Dirk B. schrieb:
> Nein. Nein.
>
> Deklaration = Typ und Name der Variablen werden „nur“ bekannt gegeben
> Definition = Die Variable wird angelegt (in C ist das gleichzeitung noch
> eine Deklaration) Es wird Speicher verbraucht.
> Initialisierung = erstmalige Wertzuweisung (bei der Definition)

Haarspalterei um die es hier nicht geht. Der TO wollte nur wissen was es 
mit extern auf sich hat und das habe ich in meinem letzten Post deutlich 
erklärt.
Das eine Deklaration keinen Speicher belegt, eine Definition dagegen 
schon, das eine Initialisierung eine Erstzuweisung ist welche dazu führt 
dass Speicher belegt wird sind Details die der TO hier nicht wissen 
will.

von Dirk B. (dirkb2)


Lesenswert?

Vudoh schrieb:
> Haarspalterei um die es hier nicht geht. Der TO wollte nur wissen was es
> mit extern auf sich hat und das habe ich in meinem letzten Post deutlich
> erklärt.

eher undeutlich.

> Das eine Deklaration keinen Speicher belegt, eine Definition dagegen
> schon,

ist der entscheidende Unterschied

> das eine Initialisierung eine Erstzuweisung ist welche dazu führt
> dass Speicher belegt wird

Das passiert schon durch die Definition.

> sind Details die der TO hier nicht wissen
> will.

Aber für dich ist es interessant, da du es falsch vermittelst.

von Vudoh (Gast)


Lesenswert?

Es wird schon wieder abgedriftet hier, je einfacher das Thema desto 
schlimmer. Mein Rat an den TO ist, sich nicht in Details zu verlieren. 
Daher fasse ich nochmal zusammen:

Das Schlüsselwort "extern" besagt schlicht und ergreifend nur, dass die 
Variable in einer anderen d.h. "externen" Datei definiert wird.

So etwas sollte man vermeiden, denn es kommt meist in Code vor der zu 
viele globale Variablen nutzt.

Um nochmal auf den Unterschied zwischen Deklaration und 
Definition/Initialisierung hinzuweisen:

Eine Deklaration ist z.B. das hier und belegt keinen Speicher:
int zahl;
Ob extern davor steht oder nicht ändert nichts daran.

Eine Definition und automatisch auch eine Initialisierung ist z.B. das 
hier:
int zahl = 10;
Oder andere Schreibweise:
int zahl {10};
Definition/Initialisierung reserviert Speicher.

von Vudoh (Gast)


Lesenswert?

Und noch eine Ergänzung: Deklarationen kann es beliebig viele von z.B. 
ein und derselben Variable geben, deshalb kann sie ja auch in einer 
Datei deklariert und in einer anderen definiert sein.

von Wilhelm M. (wimalopaan)


Lesenswert?

Vudoh schrieb:
> Eine Deklaration ist z.B. das hier und belegt keinen Speicher:
> int zahl;

Falsch: das ist eine Definition (ohne Initializer, was bedeutet, je 
nachdem, static-storage oder nicht, ob eine zero-initialisation 
stattfindet).

Vudoh schrieb:
> Oder andere Schreibweise:
> int zahl {10};

Und das geht so nur in C++, In C muss es:
1
 
2
int zahl = {10};
3
int zahl = 10;

sein.

von Dirk B. (dirkb2)


Lesenswert?

Vudoh schrieb:
> Eine Deklaration ist z.B. das hier und belegt keinen Speicher:
> int zahl;

Nein.
Das ist eine Definition (mit impliziter Deklaration) und die belegt 
schon Speicher.

> Ob extern davor steht oder nicht ändert nichts daran.

Das extern ändert es zu einer reinen Deklaration.

Die Initialisierung ist optional und nur bei einer Definition sinnvoll 
und erlaubt.

Das extern ist ja nur bei globalen Variablen sinnvoll und die werden, 
wenn nichts anderes angegeben wird, mit 0 initialisiert.

Man kann das extern auch bei der Deklaration von Funktionen mit angeben.
Aber da ist das redundant. Darum wird es i.A. weggelassen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Vudoh schrieb:
> Daher fasse ich nochmal zusammen:

Lies es selbst nochmal nach:

https://en.cppreference.com/w/c/language/declarations

bzw. kauf Dir ein Buch.

von Rolf M. (rmagnus)


Lesenswert?

Vudoh schrieb:
> Es wird schon wieder abgedriftet hier, je einfacher das Thema desto
> schlimmer. Mein Rat an den TO ist, sich nicht in Details zu verlieren.

Und doch bist du derjenige, der immer diese Details anbringt, aber 
leider falsch.

> Um nochmal auf den Unterschied zwischen Deklaration und
> Definition/Initialisierung hinzuweisen:
>
> Eine Deklaration ist z.B. das hier und belegt keinen Speicher:
> int zahl;
> Ob extern davor steht oder nicht ändert nichts daran.

Das ist falsch! Mit extern ist es nur eine Deklaration, ohne ist es auch 
eine Definition und belegt Speicher.

> Eine Definition und automatisch auch eine Initialisierung ist z.B. das
> hier:
> int zahl = 10;

Ob man explizit initialisiert oder nicht, ist egal für die Frage, ob es 
eine Definition ist oder nicht.

> Oder andere Schreibweise:
> int zahl {10};

Auch das ist in diesem Fall falsch, da das zwar für C++ gilt, nicht aber 
für C, nach dem hier gefragt wurde. Das ist aber auch wieder so ein 
Detail, das du nicht hättest anbringen müssen, nur um dich nachher 
darüber zu beschweren, dass über nicht relevante Details diskutiert 
wird.

von A. S. (Gast)


Lesenswert?

Vudoh schrieb:
> So etwas sollte man vermeiden, denn es kommt meist in Code vor der zu
> viele globale Variablen nutzt.

Selbst das ist falsch, bzw ein eigenes Thema, dass hier wirklich keine 
Rolle spielt.

Wenn Du eine Variable in 2 Files nutzt, dann sollte in einem Header ein 
extern dazu sein. Wenn Du stattdessen eine Funktion nutzt, dann sollte 
die auch in einem Header deklariert sein, braucht aber kein extern 
davor. (Weil der Compiler das auch ohne extern am ; statt {} erkennen 
kann.)

von Vudoh (Gast)


Lesenswert?

Dirk B. schrieb:
> Vudoh schrieb:
>> Eine Deklaration ist z.B. das hier und belegt keinen Speicher:
>> int zahl;
>
> Nein.
> Das ist eine Definition (mit impliziter Deklaration) und die belegt
> schon Speicher.

Nein falsch. Wenn ich einen Namen einführe und dessen Typ angebe ist das 
NUR eine Deklaration. Sobald ein Wert zugewiesen wird, wird Speicher 
reserviert. Siehe Link von Wilhelm.

von Vudoh (Gast)


Lesenswert?

Ok jetzt muss ich mich aber öffentlich für mein Halbwissen was 
Deklarationen und Definitionen angeht entschuldigen und ich entschuldige 
mich auch bei allen die ich angegriffen habe!

Ich wollte wirklich kein Halbwissen verbreiten!

Hier ein Auszug aus einem Buch bzgl. EXTERN:

The extern keyword used in the second declaration of x simply states 
that this
declaration of x isn’t a definition. It is rarely useful....usw.

von MaWin (Gast)


Lesenswert?

Rolf M. schrieb:
> Das ist falsch!

Stimmt, (fast) alles falsch!

Üblicherweise bindet man den header am Anfang ein, aber das muss nicht 
sein. #include ... kann an beliebiger Stelle stehen und dann wird es 
spannend.

Also: Wenn - was natürlich totaler Nonsens ist - eine Definition im 
header seht und das #include innerhalb einer Funktion erfolgt ...

Nur einmal so für Euch Picometer-Messer.

von A. S. (Gast)


Lesenswert?

MaWin schrieb:
> Also: Wenn - was natürlich totaler Nonsens ist - eine Definition im
> header seht und das #include innerhalb einer Funktion erfolgt ...

Es macht wenig Sinn, sich unkonventionelle Konstellation auszumalen. Dem 
TO bringt das nichts, und Du und ich wissen so halbwegs, was wann 
passiert und könnten es nutzen, bzw tun es vermutlich sogar. Der 
Klassiker ist wohl das einbinden reiner Daten (cst) in eine 
Datenstruktur. Sobald jemand weiss, was ein include macht, weiss er das.

von Wilhelm M. (wimalopaan)


Lesenswert?

Vudoh schrieb:
> Siehe Link von Wilhelm.

Vudoh schrieb:
> Ok jetzt muss ich mich aber öffentlich für mein Halbwissen was
> Deklarationen und Definitionen angeht entschuldigen und ich entschuldige
> mich auch bei allen die ich angegriffen habe!

Nun weißt Du es besser ;-)

Was man Dir allerdings im Gegensatz zu vielen anderen hier zu Gute 
halten muss, ist, dass Du das erkannt hast es auch hier sagst.

Das ist im echten Leben zwar normal aber hier in diesem Forum eher 
selten. Wie auch hier die Unsitte verbreitet ist, alles nochmal selbst 
zu wiederholen, auch wenn es von anderen schon längt genau so gesagt 
worden ist.

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.