1 Theorie | |
→ | 1.1 Die Programmiersprache C |
Bei der Aufteilung sollten wiederverwertbare Quelltext-Teile in
separate Module (Quelltextdateien) ausgegliedert werden.
Inhaltlich zusammengehörende Teile werden dabei gemeinsam in einem
Modul untergebracht.
Die Prototypen der Funktionen eines Modules - z.B. modul.c -
müssen allen anderen Modulen, die diese Funktionen benutzen wollen,
bekannt gemacht werden.
Hierzu könnte man die Prototypen manuell in die anderen Module
eintragen.
Einfacher ist es, die Prototypen in einer Header-Datei modul.h
zusammenzufassen. Diese Datei wird dann mit
#include <modul.h>
in den anderen Modulen eingebunden.
Nach Änderungen an den Funktionen des Modules muss dann nur die
Header-Datei bearbeitet werden, die Prototypen stehen dann den
anderen Modulen zur Verfügung.
#ifndef DATEINAME_H_INCLUDED #define DATEINAME_H_INCLUDED 1und am Ende:
#endifDie bedingte Compilierung wird später im Abschnitt Präprozessor erklärt.
extern "C" Prototypwird ein C-Symboltabelleneintrag erzeugt, wenn der C++-Compiler benutzt wird.
Der prinzipielle Aufbau einer Header-Datei sieht somit folgendermaßen aus:
#ifndef DATEINAME_H_INCLUDED #define DATEINAME_H_INCLUDED 1 /* Datentyp-Definitionen - falls vorhanden - stehen hier */ /* Konstanten-Definitionen - falls vorhanden - stehen hier */ #ifdef __cplusplus extern "C" { #endif /* Prototypen stehen hier */ #ifdef __cplusplus } #endif #endif /* ifndef DATEINAME_H_INCLUDED */
Die Sichtbarkeit von Variablen und Funktionen wird über die Speicherklasse festgelegt.
Ohne Angabe einer Speicherklasseklasse sind Funktionen global sichtbar, d.h. sie können von Funktionen sowohl aus dem eigenen Modul als auch von Funktionen aus anderen Modulen aufgerufen werden.
Für Variablen ohne Angabe einer Speicherklasse wird ebenfalls ein Symboltabelleneintrag erstellt, d.h. aus anderen Modulen kann auf die Variable zugegriffen werden.
Wird einer Funktion oder einer auf Datei-Ebene deklarierten
Variable die Speicherklasse "static" vorangestellt, legt der
Compiler keinen Symboltabelleneintrag für die Funktion oder
Variable an.
Die entsprechende Funktion oder Variable ist nur innerhalb des
jeweiligen Modules sichtbar.
Wird das Schlüsselwort "static" weggelassen, ist auch ein Zugriff
aus anderen Modulen möglich.
Wird eine Variable in einer Funktion mit der Speicherklasse
static definiert, wird diese Variable in persistentem Speicher
abgelegt und nicht in dem temporär während der Abarbeitung der
Funktion genutzten Stackbereich.
Zwischen verschiedenen Funktionsaufrufen behält die Variable ihren
Wert bei.
Die Speicherklasse "extern" vor einer Variablendeklaration gibt an, dass die Variable nicht hier definiert werden soll, sondern bereits in einem anderen Modul existiert und diese bereits existierende Variable benutzt werden soll.
Um eine globale Variable zu verwenden, muss die Variable in einem Modul ohne die Speicherklassen "static" oder "extern" angelegt werden. In allen anderen Modulen muss die Variablendeklaration mit dem Schlüsselwort "extern" versehen sein.
Funktionsargumente und Variablen in einer Funktion können mit
der Speicherklasse "register" deklariert werden. Der Compiler
versucht dann, Code so zu erzeugen, dass der Variablenwert die
ganze Zeit in Prozessorregistern gehalten wird und nicht in den
Hauptspeicher geschrieben werden muss.
Da jeder Prozessor nur eine begrenzte Anzahl an Registern hat,
sollte diese Optimierung mit Bedacht eingesetzt werden. Kandidaten
für eine solche Optimierung sind Funktionen mit einer sehr kleinen
Anzahl an Argumenten/Variablen, die ihrerseits keine anderen
Funktionen aufrufen.
Moderne Compiler optimieren die Zuweisung von Variablen zu
Prozessorregistern selbständig, die Speicherklasse "register"
sollte nur in seltenen Ausnahmefällen benutzt werden.
Als Beispiel soll das Programm ex018 dienen, dieses berechnet den Flächeninhalt von Quadraten oder Rechtecken.
Das Hauptprogramm steht in der Datei ex018.c.
Das Programm gibt zunächst einen Hinweistext aus, dass eine Kennziffer für die gewünschte Berechnung eingegeben werden soll. Mit der Funktion hsm_et_read_int() wird ein int-Wert von der Standardeingabe gelesen und in der Variablen aktion gespeichert.
Falls das Einlesen erfolgreich war, wird mit dem Programm fortgefahren, andernfalls abgebrochen.
Falls Kennziffer 1 eingegeben wurde, verzweigt das Programm in die Funktion quadrat(), für Kennziffer 2 in die Funktion rechteck(). Andernfalls wird eine Fehlermeldung wegen der ungültigen Kennziffer ausgegeben.
Die Funktionen quadrat() und rechteck() benutzen
die Funktion hsm_et_read_double(), um die Seitenlänge bzw.
die Seitenlängen einzulesen.
Diese Funktion ist im Modul he-read.c definiert. Der
Prototyp ist in der Datei he-read.h deklariert.
Anschließend werden die Funktionen hsm_et_geom_quadrat_flaeche() bzw. hsm_et_geom_rechteck_flaeche() benutzt, um den Flächeninhalt auszurechnen. Diese Funktionen sind in he-geom.c definiert, die Prototypen stehen in he-geom.h.
Die Funktionen hsm_et_read_int() und hsm_et_read_double() benutzen wiederum die Funktion hsm_et_str_chomp(), um den Anfang des Textes in einem Puffer zu suchen und um abschließende Leerzeichen abzuschneiden. Diese Funktion ist in he-strch.c definiert, der Prototyp steht in he-strch.h.
Es müssen also folgende Quelltexte in das Projekt ex018 eingebunden werden:
Das Verzeichnis, das he-read.h, he-geom.h, he-strch.h ... enthält, muss im Pfad der Include-Verzeichnisse aufgeführt sein.
Quelle: CERT C Coding Standard 〈1〉
#ifndef DATEINAME_H_INCLUDED #define DATEINAME_H_INCLUDED 1 /* Eigentlicher Inhalt der Header-Datei */ #endif
static int masse; double quadermasse(double a, double b, double c, double rho) { double masse; /* UEBERDECKT MODULWEITE VARIABLE! */ masse = a * b * c * rho; return masse; }
#ifndef ABCXYZ_H_INCLUDED /** Schutz vor mehrfacher Inklusion. */ #define ABCXYZ_H_INCLUDED 1 /* ... Inhalt der Header-Datei */ #endif
/** @file Datei.h Kurze Zusammenfassung. Funktionen fuer dieses und jenes. */
/** @file Datei.c Kurze Zusammenfassung. Funktionen fuer dieses und jenes. */Im Normalfall ist die Beschreibung in *.h- und *.c-Datei identisch.
1 | http://www.securecoding.cert.org |