Bereiche und Dateien

In C wird Programmcode mittels geschweifter Klammern {} in Bereiche eingeteilt, welche im englischen als scopes bezeichnet werden. Bereiche definieren grundsätzlich die Zusammengehörigkeit von Anweisungen und Symbolen und kommen bei verschiedenen Elementen der Sprache C zum Einsatz. Bereiche können ineinander verschachtelt werden, wobei der äusserste Bereich durch die Implementations-Datei begrenzt ist und als der globale Bereich bezeichnet wird.

begin file
begin global scope


begin function scope

begin while scope


end while scope

end function scope
end global scope
end of file


#include <stdio.h>

int main(){ 
  int a = 5;
  while(a > 0){ 
    printf("%d\n", a);
    a--;
  }
  return 0;
}

Details

Bereiche werden stets mittels geschweifter Klammern {} umfasst und innerhalb eines Bereiches können wiederum beliebig viele Bereiche enthalten sein. Bereiche können somit ineinander verschachtelt werden, wobei die Klammerung wohlgeformt sein muss (Jede schliessende Klammer muss mittels einer eindeutigen öffnenden Klammer eingeleitet worden sein). Um Bereiche visuell besser hervorzuheben, wird Programmcode innerhalb eines Bereiches üblicherweise um einen Tab-Schritt eingerückt.

Bereiche haben insbesondere zwei Funktionen: Die Strukturierung von Code und die Festlegung der Sichtbarkeit von Symbolen.

Code-Strukturierung

Die eine Aufgabe von Bereichen ist das Unterteilen von Programmcode in ausführbare Codeblöcke: Die in geschweiften Klammern enthaltenen Anweisungen werden als zusammengehörig betrachtet. Grundsätzlich kann ein Bereich im Programmtext einfach durch die Verwendung von öffnenden und schliessenden geschweiften Klammern inmitten des Programmtextes definiert werden. Diese Methode wird jedoch in dieser rohen Form kaum verwendet. Viel häufiger wird diese Methode im Zusammenhang mit Kontrollstrukturen verwendet. Durch die Angabe eines Bereiches bei einer Kontrollstruktur werden vom Compiler sämtliche Anweisungen innerhalb des Bereiches als zusammengehörig betrachtet, was dann als Anweisungsblock bezeichnet wird.

Bei der Definition einer Funktion werden ebenfalls die geschweiften Klammern verwendet, um festzulegen, dass jeglicher Programmcode, der sich innerhalb des Funktions-Bereiches befindet, zu der betreffenden Funktion gehört.

Symbole

Die zweite (und weitaus wichtigere) Aufgabe von Bereichen ist die Regelung der Sichtbarkeit von Symbolen über verschiedene Bereiche hinweg.

Grundsätzlich gilt für einen Bereich: Alle Symbole, welche innerhalb eines Bereiches deklariert oder definiert werden, sind für Programmtext ausserhalb des Bereiches unsichtbar. Programmtext, welcher sich innerhalb eines Bereiches befindet, kann jedoch auf Symbole ausserhalb des Bereiches zugreifen. Diese Basisregeln sind genauso gültig, wenn die Bereichsklammerung ineinander verschachtelt ist, die Beziehung somit über mehr als eine Bereichsgrenze hinaus geht: Von aussen nach innen ist nichts sichtbar, von innen nach aussen alles.

Innerhalb eines Bereiches darf in C ein Symbol nur einmal definiert werden. Symbolnamen in anderen Bereichen (ausserhalb, sowie innerhalb) werden nicht in Betracht gezogen. Falls mehrere Symbole mit demselben Namen über mehrere Bereichshierarchien hinweg definiert sind, wird bei der Programmausführung stets das Symbol angesprochen, welches im aktuellen Bereich das innerstmögliche darstellt. Existiert ausserhalb des aktuellen Bereiches somit ein gleichnamiges Symbol, so kann dieses in C nicht angesprochen werden. Auf Englisch nennt sich dies Shadowing, sprich, das Symbol ausserhalb wird in den Schatten gestellt.

Weitere Eigenschaften von Symbolen innerhalb von Bereichen können bei den Anweisungs-Blöcken nachgelesen werden.

Dateien: Der globale Bereich

Programmcode von C wird in einfache Textdateien geschrieben. Diese Dateien werden als Quell-Dateien oder auf Englisch als Source-Files bezeichnet. Es wird grundsätzlich zwischen Implementations-Dateien und Header-Dateien unterschieden. Heutige Entwicklungsumgebungen nehmen automatisch jede Implementations-Datei als Startpunkt für den Compiler an. Die Header-Dateien werden vom Compiler nicht direkt angesprochen, sondern sie werden mittels der Preprozessor-Direktive #include in die zu kompilierende Implementations-Datei eingebunden.

Header-Dateien haben normalerweise die Dateiendung .h und beinhalten hauptsächlich Deklarationen. In gewissen Fällen finden sich innerhalb von Header-Dateien auch Definitionen, beispielsweise bei der Verwendung von inline Funktionen.

Implementations-Dateien werden in C mit der Dateiendung .c gekennzeichnet. In Implementationsdateien werden hauptsächlich Definitionen geschrieben. Durch Einbindung von Header-Dateien kann zusätzliche Funktionalität angesprochen werden, deren Ausprogrammierung sich in anderen c-Dateien oder gar in vorkompilierten Objekt-Dateien wie beispielsweise Bibliotheken befindet. Mehr Informationen dazu können beim Linker nachgelesen werden.

Für jede Implementationsdatei nimmt der Compiler zu Beginn den globalen Bereich an. Korrekterweise wird dieser Bereich auf Englisch file-scope genannt. Hier auf ManderC wird auf eine Verwendung dieses Begriffes verzichtet und stattdessen von einem globalen Bereich gesprochen. Alle Symbole, welche in diesem nicht-{}-umklammerten Bereich deklariert oder definiert werden, sind globale Symbole und können überall angesprochen werden. Im globalen Bereich befindet sich immer auch die main-Funktion. Diejenige Datei, welche die main-Funktion beinhaltet, wird als die Primäre Quelldatei bezeichnet.

Im globalen Bereich darf grundsätzlich kein ausführbarer Programmcode stehen. Sämtlicher Code muss innerhalb von Funktions-Bereichen stehen. Initialisierungen von globalen Variablen sind jedoch erlaubt. In C sind diese jedoch auf konstante Werte beschränkt.

In der modernen Programmierung sind globale Symbole verpönt, allerdings sind sie nicht verboten. So werden sie nach wie vor dann benutzt, wenn beispielsweise ein kleines Programm geschrieben werden muss, welches mehr auf Funktionalität denn auf durchdachte Strukturierung getrimmt ist (quick and dirty). Ausserdem ist zu bemerken, dass Compiler und Linker selbst teilweise globale Variablen implizit definieren, wodurch das Programm erst lauffähig wird (siehe dazu Runtime-System).

Nächstes Kapitel: Code-Style-Guides und Code Analyzers