Die Lebensdauer eines Datums, und damit auch dessen Sichtbarkeit, hängt u.a. von der Stelle seiner Definition im Programm ab.
Ein Datum, welches nicht innerhalb eines Blocks {...} definiert ist, wird als globales Datum bezeichnet. Es ist ab der Stelle im Programm gültig, an dem es definiert ist. Seine Gültigkeit endet am Modulende (Dateiende). Eine globale Variable wird vor dem Eintritt in die Funktion main() mit 0 initialisiert.
Ein Datum, das innerhalb einer Funktionen (wie z.B. innerhalb von main()) definiert ist, wird als lokales Datum bezeichnet. Ein lokales Datum ist nur in der Funktion gültig, in der es definiert ist. Es wird nicht automatisch initialisiert und hat damit zu Beginn einen zufälligen Inhalt.
Ein Datum, das innerhalb eines Blocks {...} definiert ist, verhält sich wie ein lokales Datum. D.h., es wird nicht automatisch initialisiert und verliert beim Verlassen des Blocks seine Gültigkeit.
Wird ein globales Datum durch ein funktions- oder blocklokales Datum verdeckt, kann mithilfe des Gültigkeitsbereichsoperators :: (scope resolution operator, das sind zwei Doppelpunkte!) vor dem Variablennamen auf das globale Datum zugegriffen werden.
#include <iostream>
#include <format>
// Daten mit Modul-Lebensdauer
int ivar1;
void PrintIVar1()
{
// Lokales Datum
int counter = 1;
// Lokales und globales Datum ausgeben
std::cout << std::format("{}. Aufruf: ivar1={}\n", counter,ivar1);
}
void PrintIntData(int val)
{
// Gibt lokales Datum (Parameter) aus
std::cout << std::format("int-Datum = {}\n", val);
}
int main()
{
ivar1 = 10; // Globales Datum setzen
PrintIVar1();
// Schleifenzaehler ivar1 ist nur im for-Block gueltig
// und 'ueberschreibt' das gleichnamige globale Datum
for (int ivar1 = 0; ivar1 < 3; ivar1++)
{
if (ivar1 != 1)
PrintIntData(ivar1); // Gibt lokales ivar1 aus
else
PrintIntData(::ivar1); // Gibt globales ivar1 aus
}
}
Um einem Datum eine durch seine Definition abweichende Sichtbarkeit bzw. Lebensdauer zuzuordnen, wird vor dem Datentyp des Datums einer der nachfolgenden Spezifizierer angegeben.
Ein Datum Daten oder eine Funktion der Speicherklasse extern teilt dem Compiler mit, dass seine Definition in einem anderen Modul (Quellcode-Datei) erfolgt als im aktuellen.
Eine etwas andere Wirkung besitzt die Speicherklasse extern bei einer benannten Konstante. Soll eine benannte Konstante in verschiedenen Modulen verwendet werden, muss sie sowohl bei ihrer Definition als auch bei den Verweisen darauf als externe Konstante definiert werden. Hierbei ist zu beachten, dass die Konstante nur einmal initialisiert werden darf.
// Datei1.cpp
#include <iostream>
#include <format>
// Globale int-Variable
int ivar = 10;
// Globale Konstante, muss bei Definition ebenfalls als
// extern definiert werden, um den Zugriff von weiteren
// Quellcode-Dateien zu erlauben
extern const int civar = 100;
// Funktion AnyFunc ist in einer anderen Quellcode-Datei definiert
extern void AnyFunc();
int main()
{
// Ausgabe der Daten
std::cout << std::format("main: ivar = {}, civar = {}\n", ivar, civar);
// Aufruf der externen Funktion AnyFunc()
AnyFunc();
}
// Datei2.cpp
#include <iostream>
#include <format>
// ivar ist in einer anderen Quellcode-Datei definiert
extern int ivar;
// Konstante ist in einer anderen Quellcode-Datei definiert
// und darf daher nicht initialisiert werden!
extern const int civar;
// Globale Funktion, wird von main() aufgerufen
void AnyFunc()
{
std::cout << std::format("AnyFunc: ivar = {}, civar = {}\n", ivar, civar);
}
Ein globales Datum oder eine Funktion der Speicherklasse static ist nur in dem Modul sichtbar, in dem es/sie definiert ist.
Ein lokales Datum der Speicherklasse static behält seinen letzten Wert auch dann bei, wenn sein Gültigkeitsbereich verlassen wird, d.h., es wird beim Verlassen des Gültigkeitsbereichs nicht gelöscht. Auf das statische Datum kann aber weiterhin nur innerhalb dessen Gültigkeitsbereich zugegriffen werden.
#include <iostream>
#include <format>
// Globale Variable ivar ist nur in dieser Quellcode-Datei sichtbar
static int ivar;
// Funktion zur Ausgabe einer Seitenzahl
void PrintFooter()
{
// Statische Variable fuer die Seitenzahl
static unsigned short page = 1;
// Seitenzahl ausgeben
std::cout << std::format("Seite {}\n", page);
// Seitenzahl erhoehen
page++;
}
int main()
{
// Einige Seitenzahlen ausgeben
for (ivar = 0; ivar<3; ivar++)
PrintFooter();
}
Die mutable Speicherklasse spielt nur im Zusammenhange mit Klassen eine Rolle und ist nur der Vollständigkeit halber hier erwähnt. Mehr dazu später bei der Einführung von Klassen.
Der const Qualifizierer kennzeichnet u.a. ein Datum, das nach seiner Definition nicht mehr veränderbar ist (siehe auch Kapitel Daten).
Später werden wir uns diesen Qualifizierer nochmals ansehen, und zwar im Zusammenhang mit Klassen.
Ein als volatile definiertes Datum weist den Compiler an, keine Optimierung bezüglich des Inhalts des Datums vorzunehmen. Typische volatile Daten sind Daten, die vom Betriebssystem bereitgestellt werden (z.B. die Systemzeit) oder in Interrupt-Routinen verändert werden.
#include <iostream>
#include <format>
// Funktion zur Berechnung des gleitenden Mittelwerts
// Die Funktion erhaelt nacheinander Einzelwerte und
// berechnet daraus den aktuellen Mittelwert und gibt
// diesen zurueck
float Average(int val)
{
static int sum = 0; // Statische Summe
static int count = 0; // Statische Anzahl der Wert
sum += val;
count++;
return static_cast<float>(sum) / static_cast<float>(count);
}
int main()
{
for (int index = 10; index != 15; index++)
std::cout << std::format("Wert: {}, Mittelwert: {:.2f}\n", index, Average(index));
}