Geltungsbereich von Variablen
|
Willemers Informatik-Ecke
Der Geltungsbereich von Variablen ist bereits bei der Beschreibung von
Blöcken zur Sprache gekommen. Im Zusammenhang mit Funktionen bekommt der
Geltungsbereich von Variablen eine besondere Bedeutung. Funktionen sollten so
geschrieben werden, dass sie nach außen möglichst abgeschlossen sind.
Das betrifft insbesondere die Variablen.
Globale Variablen
Variablen, die außerhalb aller Funktionen definiert sind, gelten in allen
Funktionen. Beim Programmstart werden sie erzeugt und initialisiert.
Beim Programmende werden sie zerstört.
Bei ihrer Erzeugung werden globale Variablen zwar auf 0 gesetzt,
dennoch sollten Sie auch globale Variablen initialisieren.
Deklaration
Auch für globale Variablen können Prototypen erstellt werden. Diese werden
auch als Deklarationen angesprochen. Eine Deklaration unterscheidet sich von
der Definition einer Variable darin, dass keinerlei Speicher für die
Variable angelegt wird. Eine Deklaration macht eine Variable bekannt. Sie
gibt also an, welchen Namen und welchen Typ sie hat. Darum ist jede Definition
auch immer eine Deklaration. Eine Variable kann nur einmal definiert, aber
beliebig oft deklariert werden, sofern die Deklarationen übereinstimmen.
extern
Eine Variable wird deklariert, ohne sie zu definieren, indem ihr das
Schlüsselwort extern vorangestellt wird.
Dabei muss extern nicht bedeuten, dass die Variable in einer anderen
Datei stehen muss. Es heißt nur, dass dies keine Variablendefinition, sondern
eine Deklaration ist.
[Deklaration einer Variablen]
enum tToken = { ... };
extern tToken aktuellesToken;
tError liesNummer(char *SourcePos)
{
...
aktuellesToken = NUMBER;
...
}
...
tToken aktuellesToken = 0;
In den meisten Fällen sollten Sie es anstreben, globale Variablen zu
vermeiden. Zu viele globale Variablen führen leicht dazu, dass die Übersicht
und die Flexibilität eines Programms verloren geht.
Die Informationsübergabe zwischen Funktionen gehört eigentlich in die
Parameter. Und wenn Informationen über die Dauer eines Funktionsaufruf hinweg
benötigt werden, sollte eine statische Variable verwendet werden.
In einigen wenigen Fällen, in denen eine geringe und übersichtliche Zahl von
globalen Variablen in nahezu jeder Funktion benötigt wird, kann der Einsatz
globaler Variablen die Schnittstellen der Funktionen erheblich vereinfachen.
Lokale Variablen
Wird innerhalb eines Funktionsblocks eine Variable definiert, spricht man
von einer lokalen Variablen. Außerhalb der Funktion kann nicht auf diese
Variable zugegriffen werden. Sie wird erzeugt und initialisiert, wenn
die Definition ausgeführt wird. Sie wird freigegeben, wenn der Block,
in dem sie definiert ist, verlassen wird.
Hintergrund
Lokale Variablen werden auf dem Stack
angelegt. Dort liegen auch die Rücksprungadresse der aufrufenden Funktion
und die Aufrufparameter. Dieser Speicher kann nach Verlassen der Funktion
leicht wieder freigegeben werden. Im Gegensatz zu globalen
Variablen wird der Speicherbereich des Stacks nicht vor Ihrer Benutzung
mit 0 belegt. Der Speicherbereich dieser
Variablen wird nach Verlassen des Blocks wieder freigegeben, aber nicht
gelöscht. Aus diesem Grund sind nicht initialisierte lokale Variablen in
einem undefinierten Zustand und mit hoher Wahrscheinlichkeit nicht 0.
Wo immer es sich anbietet, sollten Sie lokale Variablen verwenden. Damit
erreichen Sie, dass Funktionen keine unübersichtlichen Seiteneffekte auf
globale Variablen haben. Der Speicher wird
optimal genutzt, weil er von jeder Funktion nur so lange in Anspruch genommen
wird, wie er gebraucht wird. Auch wenn dieses Problem Sie noch nicht berührt:
Funktionen, die globale oder statische Variablen
nutzen, können mit großer Wahrscheinlichkeit nicht parallel
gestartet werden.
Parameter
Die Variablen der Parameterdefinition sind ebenfalls lokale Variablen.
Sie werden auf dem Stack angelegt und bei Verlassen der Funktion wieder
freigegeben. Sie werden durch die Aufrufparameter initialisiert.
Lediglich Referenzvariablen sind nicht lokal, sondern ein Verweis auf die
Variablen des Aufrufers.
Statische Variablen
Lokale Variablen können als statisch definiert werden.[1]
Statische Variablen
werden erzeugt und initialisiert, wenn ihre Definition zum ersten Mal
durchlaufen wird.
Die Variable und ihr Inhalt bleiben dann bis zum Ende des Programms erhalten.
Um eine Variable als statische Variable zu definieren, wird der Definition
das Schlüsselwort static vorangestellt.
Sichtbarkeit
Die Variable ist nur in dem Block sichtbar, in dem sie definiert wurde. Im
Gegensatz zu einer globalen Variablen kann auf sie nicht von außerhalb
zugegriffen
werden.
Eine statische Variable ist also das Mittel der Wahl, wenn eine Funktion eine
Art Gedächtnis dafür braucht, was beim letzten Funktionsaufruf ausgeführt
worden ist.
Beispiel
Im folgenden Beispiel werden die drei Variablenarten verglichen und das
unterschiedliche Verhalten demonstriert.
[static-Variable]
#include <iostream>
using namespace std;
int globvar = 1;
void myfunc()
{
static int statvar = 1;
int locvar = 1;
cout << "statisch: " << statvar;
cout << " global: " << globvar;
cout << " lokal: " << locvar << endl;
statvar++;
globvar++;
locvar++;
}
int main()
{
myfunc();
myfunc();
myfunc();
locvar = 8; // dies gibt einen Compiler-Fehler
statvar = 8; // dies gibt einen Compiler-Fehler
globvar = 8; // dies funktioniert
myfunc();
myfunc();
}
Die Funktion myfunc() arbeitet mit drei Variablen. Alle werden
angezeigt und inkrementiert.
Die Funktion wird vom Hauptprogramm dreimal aufgerufen. Dann versucht das
Programm, den Variablen den Wert 8 zuzuweisen. Das wird bei locvar
und bei statvar bereits vom Compiler unterbunden. Beide Variablen
nur innerhalb der Funktion myfunc sichtbar sind.
Schließlich wird myfunc noch zweimal aufgerufen.
Nachdem die beiden Fehler aus dem Programm beseitigt
wurden, kann das Programm gestartet werden.
statisch: 1 global: 1 lokal: 1
statisch: 2 global: 2 lokal: 1
statisch: 3 global: 3 lokal: 1
statisch: 4 global: 8 lokal: 1
statisch: 5 global: 9 lokal: 1
Lokale Variable
Im Beispiel ist das unterschiedliche Verhalten der verschiedenen Variablen
zu sehen.
Das Verhalten der lokalen Variablen locvar ist am einfachsten
erklärt. Die Variable wird bei jedem Betreten der Funktion neu erzeugt und
beim Verlassen wieder zerstört. Jedes Mal wird sie auch neu initialisiert.
Darum enthält sie auch jedes Mal eine 1. Nach dem Inkrementieren hat sie
innerhalb der Funktion noch den Wert 2. Aber das nützt ihr auch nichts.
Sie wird beim Beenden der Funktion zerstört.
Globale Variable
Die globale Variable globvar wird beim Programmstart erzeugt und
initialisiert. Innerhalb der Funktion wird sie inkrementiert und angezeigt.
Da sie eine globale Variable ist, kann jede Funktion und darum natürlich
die Hauptfunktion main() auf sie zugreifen. Das wird dadurch
demonstriert, dass in main() nach dem dritten Funktionsaufruf von
myfunc() den Wert auf 8 festsetzt. Bei
den nächsten Aufrufen arbeitet die Funktion myfunc() mit diesem
veränderten Wert weiter.
Statische Variable
Die statische Variable statvar verhält sich teilweise wie eine
lokale und teilweise wie eine globale Variable. Wie eine lokale Variable
ist sie gegen Zugriffe geschützt, die von außerhalb erfolgen. Niemand kann von
außen versehentlich ihren Wert verändern. Andererseits verliert
die statische Variable beim Verlassen der Funktion nicht ihren Wert.
Die Initialisierung wird nur einmal ausgeführt, und zwar beim ersten Starten
der Funktion.
- [1]
- Sie können
auch globale Variablen als >>static<< definieren.
Das hat aber eine völlig andere Bedeutung.