C-Programmierung: Eigene Header

Eigene Module mit den entsprechenden eigenen Headern sind sinnvoll, um ein Programm in Teilmodule zu zerlegen oder bei Funktionen und Konstanten, die in mehreren Programmen verwendet werden sollen. Eine Headerdatei – kurz: Header – hat die Form myheader.h.
Sie sollte ausschließlich enthalten:

  • Funktionsdeklarationen (Prototypen)
  • Variablen-Deklarationen (extern)
  • globale Konstanten (#define, const)
  • eigene Typ-Definitionen (typedef struct,union,enum)
#ifndef MYHEADER_H
#define MYHEADER_H

#define PI (3.1416)

extern int meineVariable;

extern int meineFunktion1(int);
extern int meineFunktion2(char);

#endif /* MYHEADER_H */

Anmerkung: Die Präprozessor-Direktiven #ifndef, #define und #endif werden detailliert im Kapitel Präprozessor erklärt.

In der ersten Zeile dieses kleinen Beispiels wird ein Include-Guard verwendet, dabei überprüft der Präprozessor, ob im Kontext des Programms das Makro MYHEADER_H schon definiert ist. Wenn ja, ist auch der Header dem Programm schon bekannt und wird nicht weiter abgearbeitet. Dies ist nötig, weil es auch vorkommen kann, dass ein Header die Funktionalität eines andern braucht und diesen mit einbindet, oder weil im Header Definitionen wie Typdefinitionen mit typedef stehen, die bei Mehrfach-Includes zu Compilerfehlern führen würden.

Wenn das Makro MYHEADER_H dem Präprozessor noch nicht bekannt ist, dann beginnt er ab der zweiten Zeile mit der Abarbeitung der Direktiven im if-Block. Die zweite Zeile gibt dem Präprozessor die Anweisung, das Makro MYHEADER_H zu definieren. Damit wird gemerkt, dass dieser Header schon eingebunden wurde. Dieser Makroname ist frei wählbar, muss im Projekt jedoch eindeutig sein. Es hat sich die Konvention etabliert, den Namen dieses Makros zur Verbesserung der Lesbarkeit an den Dateinamen des Headers anzulehnen und ihn als MYHEADER_H oder __MYHEADER_H__ zu wählen. Dann wird der Code von Zeile 3 bis 10 in die Quelldatei, welche die #include-Direktive enthält, eingefügt. Zeile 11 kommt bei der Headerdatei immer am Ende und teilt dem Präprozessor das Ende des if-Zweigs (siehe Kapitel Präprozessor) mit.

Variablen allgemein verfügbar zu machen stellt ein besonderes Problem dar, das besonders für Anfänger schwer verständlich ist. Grundsätzlich sollte man den Variablen in Header-Dateien das Schlüsselwort extern voranstellen. Damit erklärt man dem Compiler, dass es die Variable meineVariable gibt, diese jedoch an anderer Stelle definiert ist.

Würde eine Variable in einer Header-Datei definiert werden, würde für jede C-Datei, die die Header-Datei einbindet, eine eigene Variable mit eigenem Speicher erstellt. Jede C-Datei hätte also ein eigenes Exemplar, ohne dass sich deren Bearbeitung auf die Variablen, die die anderen C-Dateien kennen, auswirkt. Eine Verwendung solcher Variablen sollte vermieden werden, da sie vor allem in der hardwarenahen Programmierung der Ressourcenschonung dient. Stattdessen sollte man Funktionen der Art int getMeineVariable() benutzen.

Nachdem die Headerdatei geschrieben wurde, ist es noch nötig, eine C-Datei myheader.c zu schreiben. In dieser Datei werden die in den Headerzeilen 8 und 9 deklarierten Funktionen implementiert. Damit der Compiler weiß, dass diese Datei die Funktionalität des Headers ausprägt, wird als erstes der Header inkludiert; danach werden einfach wie gewohnt die Funktionen geschrieben.

#include "myheader.h"

int meineVariable = 0;

int meineFunktion1 (int i)
{
  return (i+1);
}

int meineFunktion2 (char c)
{
  if (c == 'A') 
    return 1;
  return 0;
}

Die Datei myheader.c wird jetzt kompiliert und eine so genannte Objektdatei erzeugt. Diese hat typischerweise die Form myheader.obj oder myheader.o. Zuletzt muss dem eigentlichen Programm die Funktionalität des Headers bekannt gemacht werden, wie es durch ein #include "myheader.h" geschieht, und dem Linker muss beim Erstellen des Programms gesagt werden, dass er die Objektdatei myheader.obj bzw. myheader.o mit einbinden soll.

Damit der im Header verwiesenen Variable auch eine real existierende gegenübersteht, muss in myheader.c eine Variable vom selben Typ und mit demselben Namen definiert werden.