===Frage= |
[[Inhaltsverzeichnis]] ==Frage= |
===Antwort= |
==Antwort (kompakte Variante)= |
===Antwort (andere Variante)= |
==Antwort (ausführliche Variante)= |
===Frage= Soll das bedeuten, es ist in C nicht möglich, eine Variable, oder besser ein Objekt, im gesamten Programm anzusprechen, da der Name nicht zur Verfügung steht? ===Antwort= Doch[[Fußnote]Einschränkend soll nicht unerwähnt bleiben, daß auf einen Bezeichner natürlich nicht vor seiner Deklaration zugegriffen werden kann. "Im gesamten Programm" ist also nicht richtig.]. |
Dies bedeutet jedoch nicht, daß ein Objekt nicht im gesamten Programm ansprechbar[[Fußnote]Einschränkend soll nicht unerwähnt bleiben, daß auf einen Bezeichner natürlich nicht vor seiner Deklaration zugegriffen werden kann. "Im gesamten Programm" ist also nicht richtig.] wäre. |
: [ToDo] Hier sollten noch Belege für die Verwendung von [[Schrift][Art=courier]extern] erfolgen. |
: [InArbeit] Hier sollten noch Belege für die Verwendung von [[Schrift][Art=courier]extern] erfolgen. |
Soll auf ein solches Objekt von einer anderen Übersetzungseinheit zugegriffen werden, muß dort noch ein Bezeichner definiert werden, der auf das Objekt verweist. ===Frage= |
Soll auf ein solches Objekt von einer anderen Übersetzungseinheit zugegriffen werden, muß dort noch ein Bezeichner deklariert werden, der auf das Objekt verweist. |
Nun gut. Ich benötige die Bezeichner in vielen Dateien (Übersetzungseinheiten). Es sind ggf. sogar mehrere "globale" Bezeichner. Muß ich jetzt in jede der Dateien die entsprechenden Bezeichner deklarieren? |
===Was sonst noch zu diesem Thema gesagt werden sollte:= ====Bezeichner in einer Headerdatei zusammenfassen= |
===Antwort= Prinzipiell schon. Nur ist es besser, die Deklarationen in eine Header-Datei zu schreiben und diese dann in den gewünschten Quelltexten zu "includieren". |
Sollen Bezeichner in mehreren Übersetzungseinheiten verwendet werden, ist es ratsam, die Deklarationen in eine Header-Datei zu schreiben und diese dann in den gewünschten Quelltexten zu "includieren". Dabei ist es irrelevant, ob die Bezeichner nun auf Variablen oder Funktionen verweisen. Nachfolgend wird ein Vorgehen illustriert. |
Es fällt auf, daß auch in der Datei [[Schrift][Art=courier]a.c] die Header-Datei [[Schrift][Art=courier]a.h] eigebunden wurde. Dies ist eigendlich überflüssig. Jedoch ermöglicht diese Vorgehensweise es dem Kompiler eventuelle Unstimmigkeiten zwischen den Deklarationen in der Header-Datei [[Schrift][Art=courier]a.h] und der tatsächlichen Definition in der Quelldatei [[Schrift][Art=courier]a.c] zu erkennen. |
Es fällt auf, daß auch in der Datei [[Schrift][Art=courier]a.c] die Header-Datei [[Schrift][Art=courier]a.h] eingebunden wurde. Dies ist eigendlich überflüssig, jedoch ermöglicht diese Vorgehensweise es dem Kompiler eventuelle Unstimmigkeiten zwischen den Deklarationen in der Header-Datei [[Schrift][Art=courier]a.h] und der tatsächlichen Definition in der Quelldatei [[Schrift][Art=courier]a.c] zu erkennen. ====Bezeichner so lokal wie möglich definieren= Überlegen Sie, ob Sie einen Bezeichner wirklich in allen Übersetzungseinheiten benötigen. Sollte ein Bezeichner lediglich von einer begrenzten Anzahl von Funktionen benötigt werden, jedoch nicht allgemein ansprechbar sein, so ist es ratsam ein Objekt zu definieren, dessen Bezeichner eine interner Bindung (internal linkage) hat. Eine interne Bindung kann mit dem Speicherklassenmodifizierer [[Schrift][Art=courier]static] erreicht werden. [[Code][Breite=900][Hintergrund=blau][Farbe=gelb][Zeilennummer=ja] static int var; extern void setVar(int x) { var = x; } extern int getVar() { return var; } ] Im eben gezeigten Beispiel haben lediglich die Funktionen eine externe Bindung. Der Bezeichner [[Schrift][Art=courier]var] hat eine interne Bindung. Dies hat zur Folge, daß * dieses Objekt nicht von anderen Übersetzungseinheiten ansprechbar ist. Auch nicht mit einer namesgleichen [[Schrift][Art=courier]extern]-Deklaration. * in anderen Übersetzungseinheiten ein anderes Objekt mit dem Bezeichner [[Schrift][Art=courier]var] definiert werden kann. Diese Vorgehensweise ist nicht auf Variablen beschränkt. Ebenso kann auch eine Funktion mit interner Bindung definiert werden, wenn diese nur in dieser Übersetzungseinheit benötigt wird. :[InArbeit] -- Belege aus dem Standard angeben. |
===Frage= |
====extern bedeutet nicht external linkage= |
Was sind das für Texte in den grauen Kästen? |
Es soll nicht unerwähnt bleiben, daß die Angabe des Speichklassenmodifizierers [[Schrift][Art=courier]extern] nicht automatisch eine Deklaration eines Bezeichners mit externer Bindung zur Folge hat. [[Code][Breite=900] 6.2.2 Linkages of identifiers 4 For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,23) if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage. ] |
===Antwort= |
So kann im nachfolgenden Beispiel die Funktion [[Schrift][Art=courier]main] in der Datei [[Schrift][Art=courier]b.c] nicht auf das Objekt [[Schrift][Art=courier]var] aus der Datei [[Schrift][Art=courier]a.c] zugreifen. Stattdessen greift der Bezeichner, der in der Zeile 7 deklariert wird, auf das Objekt der gleichen Datei (mit interner Bindung) zu. |
Dies sind Zitate aus ISO/IEC 9899:1999 (E), dem aktuell gültigen C-Standard. |
[[Code][Breite=900][Hintergrund=blau][Farbe=gelb][Zeilennummer=ja] /* *** Datei: a.c *** */ int var = 5; ] [[Code][Breite=900][Hintergrund=blau][Farbe=gelb][Zeilennummer=ja] /* *** Datei: b.c *** */ #include <stdio.h> static int var = 10; int main(void) { extern int var; printf("%d\n", var); return 0; } ] Beide Dateien lassen sich, wie schon oben gezeigt, übersetzen. Das resultierende Programm gibt eine [[Schrift][Art=courier]10] und nicht eine [[Schrift][Art=courier]5] aus. [[Code][Breite=900] Die Texte in den grauen Kästen sind Zitate aus ISO/IEC 9899:1999 (E), dem aktuell gültigen C-Standard. ] |
===Resourcen= |
==Resourcen= |
===Diskussion= |
==Diskussion= |
: Ein Anfang ist gemacht --Claudio Carobolante |
: Ein Anfang ist gemacht (ursprüngliche Variante) --Claudio Carobolante |
: Du verwendest in den letzen beiden Absätzen den Begriff Variable. Du meinst das Objekt, auf welches ein Bezeichner verweist.\ |
: Du verwendest in den letzten beiden Absätzen den Begriff Variable. Du meinst das Objekt, auf welches ein Bezeichner verweist.\ |
KategorieCee |
KategorieC KategorieCee |
Frage |
Wie erzeugt man in C eine "globale Variable"?
Antwort (kompakte Variante) |
Man schreibt ganz einfach Typ und Bezeichner außerhalb von jeder Funktion hin:
|
Bei Existenz einer solchen Variablendefinition kann man überall nach Verwendung des Schlüsselwortes extern diese 'globale' Variable benutzen:
|
Die obenstehende Definition
int A;entspricht folglich quasi
public int A;wobei es Schlüsselwörter wie »public global export« (explizite Globalisierung) in C allerdings nicht gibt.
|
static gibt innerhalb von Funktionsblöcken statische Lebensdauer an.
Bei anderen Verwendungen wird »static« zweckentfremdet, denn es wirkt dabei so
als ob es »local« hieße:
static int B;erzeugt eine dateilokale Variable, die allerdings auch ohne »static« bereits statische Lebensdauer hätte.
local int B;wäre also klarer, um eine explizite Lokalisierung anzugeben.
Ein Fehler, der nicht selten vorkommt:
|
Das ist kein Widerspruch zu:
|
Antwort (ausführliche Variante) |
Es muß darauf hingewiesen werden, daß C (SpracheCee) den Begriff "globale Variable" an keiner Stelle verwendet. Dies aus gutem Grund, denn die Sprache unterscheidet zwischen den Objekten eines Programms und deren Bezeichner. Also ein Speicherplatz und der Name unter dem dieser Speicher angesprochen werden kann.
Zunächst muß geklärt werden, was mit dem Begriff Variable gemeint ist. In erster Linie ist die Frage wohl so zu verstehen, daß der Name eines Objektes, auf das zugegriffen werden soll, "global" verfügbar sein soll. Ein Name eines Objektes ist ein Bezeichner eines Objektes.
|
Wird ein Objekt, wie im oben stehenden Beispielcode, mit file scope definiert, so existiert dieses Objekt im gesamten Programm und während der gesamten Dauer der Programmausführung.
|
Anders verhält sich der Bezeichner. Dessen Gültigkeitsbereich endet mit der Übersetzungseinheit (CeeÜbersetzungsEinheit?).
|
Von einer "globalen Variablen" kann also hier nicht gesprochen werden, wenn global das gesamte Programm meint. Hier ist lediglich das Objekt "global". So scheitert der Versuch, die nachfolgend gezeigte Datei b.c zu übersetzen, auch wenn anschließend noch die Datei (deren Kompilat) a.c hinzugelinkt werden soll, die Datei a.c "gerade eben noch" vom Kompiler übersetzt wurde oder beide Dateien, beispielsweise mittels einer make-Datei, zu einem Projekt zusammengefasst werden.
|
Dies bedeutet jedoch nicht, daß ein Objekt nicht im gesamten Programm ansprechbar[1] wäre. Interessant im Zusammenhang mit der urspünglich gestellten Frage, ist wieder die Bindung (linkage) eines Bezeichners.
Sollen nun in verschiedenen Übersetzungseinheiten gleiche Bezeichner (Namen) das selbe Objekt ansprechen, so muß eine externe Bindung für alle diese Bezeichner gewählt werden.
|
Es kann also wie folgt vorgegangen werden:
Das nachfolgende Beispiel zeigt die Datei a.c mit der Erweiterung einer Funktion.
|
In der oben gezeigten Datei a.c werden die Bezeichner var und func deklariert. Beide Bezeichner haben nach 6.2.2 Abs. 5 eine externe Bindung.
Soll nun von einer anderen Übersetzungseinheit auf das Objekt var oder die Funktion func zugegriffen werden, so müssen in diesen namensgleiche Deklarationen mit externer Bindung vorgenommen werden. Die Deklarationen dürfen dabei keine neuen Objekte oder Funktionen erzeugen, es dürfen also keine Definitionen sein, da die Sprachspezifikation mehrere gleichnamige externe Objekte verbietet.
|
Der folgende Quelltext zeigt eine Beispielimplementierung.
|
Der Modifizierer extern ist bei Funktionen jedoch nicht zwangsläufig notwendig. Wird ein Bezeichner für eine Funktion deklariert und dabei kein Speicherklassenmodifizierer angegeben, so ist dies einer Angabe von extern gleichbedeutend. Zum Beleg sei der oben fehlende Teil von 6.2.2 Abs. 5 nachgereicht:
|
Wie die beiden Quelltexte übersetzt und das resultierende Programm gestartet werden kann, ist nachfolgend dargestellt[2].
|
Die Ausgabe des Programms zeigt, daß sowohl die Funktion main wie auch die Funktion func auf das gleiche Objekt über einen Bezeichner var zugreifen.
Abschließend kann also gesagt werden, dass C keine globale Namen kennt, sondern lediglich Objekte, die im gesamten Bereich der Programms ansprechbar sein können. Soll auf ein solches Objekt von einer anderen Übersetzungseinheit zugegriffen werden, muß dort noch ein Bezeichner deklariert werden, der auf das Objekt verweist.
Was sonst noch zu diesem Thema gesagt werden sollte: |
Bezeichner in einer Headerdatei zusammenfassen |
Sollen Bezeichner in mehreren Übersetzungseinheiten verwendet werden, ist es ratsam, die Deklarationen in eine Header-Datei zu schreiben und diese dann in den gewünschten Quelltexten zu "includieren". Dabei ist es irrelevant, ob die Bezeichner nun auf Variablen oder Funktionen verweisen. Nachfolgend wird ein Vorgehen illustriert.
|
|
|
Es fällt auf, daß auch in der Datei a.c die Header-Datei a.h eingebunden wurde. Dies ist eigendlich überflüssig, jedoch ermöglicht diese Vorgehensweise es dem Kompiler eventuelle Unstimmigkeiten zwischen den Deklarationen in der Header-Datei a.h und der tatsächlichen Definition in der Quelldatei a.c zu erkennen.
Bezeichner so lokal wie möglich definieren |
Überlegen Sie, ob Sie einen Bezeichner wirklich in allen Übersetzungseinheiten benötigen. Sollte ein Bezeichner lediglich von einer begrenzten Anzahl von Funktionen benötigt werden, jedoch nicht allgemein ansprechbar sein, so ist es ratsam ein Objekt zu definieren, dessen Bezeichner eine interner Bindung (internal linkage) hat. Eine interne Bindung kann mit dem Speicherklassenmodifizierer static erreicht werden.
|
Im eben gezeigten Beispiel haben lediglich die Funktionen eine externe Bindung. Der Bezeichner var hat eine interne Bindung. Dies hat zur Folge, daß
extern bedeutet nicht external linkage |
Es soll nicht unerwähnt bleiben, daß die Angabe des Speichklassenmodifizierers extern nicht automatisch eine Deklaration eines Bezeichners mit externer Bindung zur Folge hat.
|
So kann im nachfolgenden Beispiel die Funktion main in der Datei b.c nicht auf das Objekt var aus der Datei a.c zugreifen. Stattdessen greift der Bezeichner, der in der Zeile 7 deklariert wird, auf das Objekt der gleichen Datei (mit interner Bindung) zu.
|
|
Beide Dateien lassen sich, wie schon oben gezeigt, übersetzen. Das resultierende Programm gibt eine 10 und nicht eine 5 aus.
|
Resourcen |
Diskussion |
IMO sollte man das neu formulieren oder zumindest überarbeiten.
Ich halte es für eine falsche Interpretation des Standard, was hier eingangs gesagt wird. Die Aussage, C kennt keine globalen Variablen, halte ich für falsch. Die Aussage, Der Standard verwendet den Begriff "Globale Variable" nicht, ist richtig.
Wenn man in einer Übersetzungseinheit eine Variable definiert, außerhalb von Funktionen und ohne 'static', dann hat man garantiert das, was allgemein als 'Globale Variable' bekannt ist. Lediglich es wird nicht unter Verwendung des Wortes 'global' im Standard beschrieben.
Mit einer solchen Variablen muß unbedingt eine Information einhergehen, die diese Variable globalisiert, also für eventuell angegebene 'extern'-Deklarationen in eventuellen anderen Übersetzungseinheiten erreichbar macht.