2.5. Regeln beim Schreiben von C-Programmen

Formatierung

C ist eine formatfreie Sprache. Das bedeutet, daß es kaum Einschränkungen bei der äußeren Gestaltung von C-Programmen gibt und daß es in der Verantwortung des Programmierers liegt, für ein vernünftiges Aussehen seiner Programme zu sorgen. Der C-Compiler ist ziemlich anspruchslos, was die Übersichtlichkeit der Programme angeht. Man sollte aber sich selbst zuliebe für gute Lesbarkeit des Programmcodes sorgen. Formatfreiheit heißt im besonderen, daß ein Zeilenumbruch nicht wie in manchen anderen Programmiersprachen (z.B. BASIC) als Ende einer Anweisung interpretiert wird. Folgende Versionen unseres "Hello world"-Programms sind für den C-Compiler gleichermaßen akzeptabel, wenn auch für Menschen schwerer lesbar:


/* hello1.c */

#include <stdio.h>

int main(void){ printf("Hello world\n");return 0;}

/* hello2.c */
#include <stdio.h>

int main
(

void
)
{
printf
(
"Hello world\n"
)
;
return 0
;
}

Das Insistieren auf Lesbarkeit von Programmen ist mehr als nur übersteigerte Ordnungsliebe: Entgegen landläufiger Meinung verbringen die meisten Programmierer den Großteil ihrer Zeit nämlich nicht mit dem Schreiben neuer, sondern mit der Pflege, der Weiterentwicklung und dem Debuggen bestehender Programme. Unübersichtlicher und kryptisch geschriebener Code bringt den Autor bei der erneuten Begutachtung seines eigenen Werks schon nach wenigen Wochen in Verlegenheit. Erst recht ist es eine unangenehme Aufgabe, schlecht lesbaren Programmcode anderer zu verstehen. Die Erstellung wartungsfreundlicher Programme beginnt mit der Einhaltung einiger Grundregeln bei der Formatierung des Quellcodes:

Kommentierung

Es gibt zwei Arten von Programmen: verständliche und unverständliche. Um nicht ein Programm der zweiten Sorte zu produzieren, sind neben klarem Programmierstil und übersichtlicher Formatierung reichliche und aussagekräftige Kommentare erforderlich. Dabei ist es besser, in Kommentaren anzugeben, warum man diese oder jene Anweisung verwendet, anstatt festzustellen, was die Anweisung macht. Es ist z.B. relativ leicht aus einem Programmcode ersichtlich, daß der Wert einer Variable erhöht wird; für das Verständnis wichtiger ist, warum er erhöht wird.

Die meisten Programmierer schwören auf ihre eigenen Formatierungs- und Kommentierungsgewohnheiten; trotzdem reduzieren sich letztlich die gängigen Formen der Gestaltung des C-Quelltextes auf einige Grundmuster. Die hier vorgestellten Gestaltungsvorschläge verstehen sich deshalb nicht als Regeln, sondern als Empfehlungen. Die Regel hingegen lautet: Ein Programm muß so klar und deutlich wie möglich sein.

Jedes Programm sollte mit einem Kommentar beginnen, der Aufschluß darüber gibt, wie das Programm heißt, was es macht und wie es verwendet wird. Abhängig vom Kontext, in dem das Programm erstellt wird, sollen auch der Name des Autors, das Datum der letzten Änderung und eventuell zusätzliche erläuternde Bemerkungen im ersten Kommentarkasten erscheinen. Es versteht sich von selbst, daß hier für den Hobby-Programmierer andere Maßstäbe gelten als für den beruflichen Softwareentwickler.

Der Beginn von Programmblöcken sollte ebenfalls mit Kommentaren versehen werden, die erläutern, was im bevorstehenden Abschnitt zu erwarten ist. Ebenso soll vor der Definition von Funktionen klar gemacht werden, was die Funktion macht und welche Argumente ihr übergeben werden. Auch bei der Definition von Variablen ist es hilfreich, wenn aus Erläuterungen hervorgeht, was es mit den jeweiligen Variablen auf sich hat.

Da es sich bei Programm-Quelltexten um Klartextdateien handelt, entfallen die Möglichkeiten der Hervorhebung von Text durch Kursivsetzung, Fettdruck, Unterstreichung etc. Alternativ bieten sich die Verwendung von Kommentarboxen, der Einsatz von Pfeilen und das Ziehen von Linien an, um Kommentaren die nötige Aufmerksamkeit zukommen zu lassen.




/******************************************************* 
 *                                                     *
 * Kommentarkästen stehen am Beginn von Programmen     *
 * und vor der Definition von Funktionen               *
 *                                                     *
 *******************************************************/
 
/*****************************************************
 *****************************************************
 ****** 	Wichtige Hinweise sollen die          *****
 ****** 	Aufmerksamkeit auf sich ziehen        *****
 *****************************************************
 *****************************************************/
 
/*----------> nicht so wichtige Warnung <------------*/
/* >>>> Beginn eines größeren Programmabschnitts <<<<*/

/*
 * Beginn eines kleineren Abschnitts 
 * ^^^^^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^
 */

/*
 * Einzelne Wörter, die besonders **wichtig** sind, 
 * können hervorgehoben werden
 */

Kommentarzeichen werden auch häufig verwendet, um Teile des Programmcodes, die noch einer Überarbeitung bedürfen, vor dem Compiler zu "verstecken"; diese Vorgangsweise nennt man "auskommentieren". Es ist darauf zu achten, daß solch ein auskommentierter C-Code keine Kommentare (bzw. Kommentarzeichen) enthält, weil C die Schachtelung von Kommentaren nicht zuläßt.


/* Dieser Kommentar /* führt zu einer */ Fehlermeldung */

Namen für Variablen und Funktionen

Variablen- und Funktionsnamen sind in C Kombinationen aus Buchstaben und Ziffern, wobei das erste Zeichen ein Buchstabe sein muß. Zusätzlich erlaubt ist der Unterstrich "_", der als Buchstabe behandelt wird und daher auch als erstes Zeichen eines Namens auftreten darf. Für die Vergabe von Variablen- und Funktionsnamen ausgeschlossen sind die reservierten Wörter von C selbst.

Gültige Namen sind z.B.:


Result	pcx2gif	_temp	day_of_week

Ungültige Namen sind dagegen:


2fach	Achtung!	int	print-all

Der ANSI-Standard verlangt, daß ein C-Compiler die ersten 31 Zeichen bei intern verwendeten Namen unterscheidet; aufgrund der Beschränkungen einiger Linker werden bei externen Namen (Namen, die in anderen C-Quelldateien definiert wurden) allerdings nur 6 Zeichen verlangt. Das bedeutet in der Praxis, daß beim Bezug auf externe Namen Probleme auftreten können, wenn nur die ersten 6 Zeichen als signifikant gelten. In jedem Fall sollte ausprobiert bzw. der Dokumentation entnommen werden, wo die Grenzen des Linkers liegen. Die meisten modernen C-Entwicklungssysteme gehen weit über dieses von ANSI sehr niedrig angesetzte Minimum hinaus. Es besteht jedenfalls kein Grund, sich deswegen gleich von der Vergabe langer, selbstdokumentierender Funktionsnamen abbringen zu lassen.

Es fällt auf, daß in unserem "Hello world"-Programm beide Funktionsnamen, nämlich main() und printf(), in Kleinschreibung gehalten sind. Auf die Schreibweise ist bei der Verwendung von Funktions- und Variablennamen unbedingt zu achten, da C zwischen Groß- und Kleinschreibung unterscheidet - oder, wie es englisch heißt, case-sensitive ist. PRINTF(), Printf() und printf() sind demnach für den C-Compiler drei verschiedene Funktionen.

Nicht alle Linker unterscheiden jedoch Groß- und Kleinschreibung. Ist dies bei einem Linker aber doch der Fall, dann würde er an der Funktion PRINTF() scheitern: Schließlich heißt die Standard-C-Funktion, die in einer der Bibliotheken abgelegt ist, printf(). Unterscheidet der Linker die Schreibweise nicht, dann würde er Funktionen, deren Namen sich nur durch Groß- und Kleinschreibung unterscheiden, wahllos zum Programm binden. Beim Aufruf von Standard-Bibliotheksfunktionen muß also die Schreibweise genau eingehalten werden, und die ist per Voreinstellung Kleinschreibung. Bei der Vergabe von Namen für selbstdefinierte Funktionen können beliebige Namen gewählt werden. Die Namen verschiedener Funktionen und Variablen sollten sich aber nicht nur durch die Schreibweise unterscheiden.

Für die Vergabe von aufschlußreichen Variablennamen haben sich mittlerweile mehrere Konventionen eingebürgert. Welcher man folgen will, ist großteils Geschmacksache, auch wenn die Vertreter der verschiedenen Schreibweisen oft von der Überlegenheit ihres Systems fest überzeugt sind. Wichtig ist nur, daß man sich konsequent an die einmal gewählte Methode der Namensgebung hält, damit Programme bei Funktions- und Variablennamen einem durchgängigen Prinzip gehorchen und dadurch leichter verständlich werden.

Leicht verständliche Namen gleichen sich darin, daß sie anhand von Präfixen oder Suffixen den Typ der Variablen dokumentieren. Dafür haben sich die Standard-Präfixe und -suffixe _ptr (für Pointer, z.B. next_ptr), _p (ebenfalls für Pointer), _file (Variablen vom Typ *FILE, z.B. in_file) oder n_ (für Nummer, z.B. n_Zeichen) herausgebildet.

Alternativ zu den eben genannten Affixen, die mit einem Unterstrich an den Namen angefügt werden, bietet sich die sogenannte Hungarian Notation an: Sie wurde von Microsoft bei der Entwicklung von Windows eingeführt und wird deshalb auch manchmal als Microsoft Notation bezeichnet. Auch diese Methode setzt Präfixe ein, die den Datentyp von Variablen oder von Rückgabewerten (bei Funktionen) bezeichnen. Der Name selbst steht in gemischter Schreibweise, wobei das erste Zeichen eines jeden Teilwortes groß gesetzt wird. (z.B. szFirstName).

Folgende Tabelle gibt einen Überblick über die gängigsten Präfixe der Hungarian Notation, von denen allerdings keine komplette Liste existiert. Die hier angeführte Aufzählung ist aus verschiedenen Quellen zusammengetragen und kann keinen Anspruch auf Vollständigkeit erheben. Teilweise werden die gleichen Präfixe zur Bezeichnung verschiedener Datentypen herangezogen, was zu Ambiguitätsproblemen führen könnte.

Die Datentypen in Großbuchstaben sind allgemein verbreitete Ersatznamen für häufig verwendete Datentypen in C. Bei den meisten C-Systemen werden diese innerhalb von Definitionsdateien mit Hilfe von typedef oder #define vordefiniert.

Präfix Datentyp
c char
by BYTE (unsigned char)
uch UCHAR (unsigned char)
s short integer
n ebenfalls für short int (steht in Konflikt mit s)
us unsigned short int
i integer
ui unsigned int
w WORD (unsigned integer)
b BOOL (usigned short)
l long
ul unsigned long int
dw DWORD (unsigned long int)
x normalerweise short int, für die x-Koordinate von Grafiken
y normalerweise short int, für die y-Koordinate von Grafiken
h HANDLE (WORD)
fn Funktion, im allgemeinen verwendet bei Pointern auf Funktionen
s Zeichenketten (nicht notwendigerweise NULL-terminiert)
sz Zeichenketten (NULL-terminiert)
p Pointer
lp long (oder far) pointer
np short (oder near) pointer