C++ Tutorial

 Daten Lebensdauer & Sichtbarkeit

Lebensdauer

Die Lebensdauer eines Datums, und damit auch dessen Sichtbarkeit, hängt u.a. von der Stelle seiner Definition im Programm ab.

Modul

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.

Funktion

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.

Block

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.

Zugriff auf globale Daten (Gültigkeitsbereichsoperator)

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
    }
}

Spezifikationen

Um einem Datum eine durch seine Definition abweichende Sichtbarkeit bzw. Lebensdauer zuzuordnen, wird vor dem Datentyp des Datums einer der nachfolgenden Spezifizierer angegeben.

extern Speicherklasse

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);
}

static Speicherklasse

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();
}

mutable Speicherklasse

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.

const Qualifizierer

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.

volatile Qualifizierer

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));
}