13.1. Neue Namen für existierende Datentypen: typedef

Mit Hilfe dieses Schlüsselworts können Sie einen Datentyp umbenennen. Dabei wird also kein neuer Datentyp erzeugt, sondern lediglich ein bereits bestehender unter einem neuen Namen angesprochen. Die allgemeine Form einer typedef-Anweisung lautet:


typedef Datentyp NeuerName;

Bei Datentyp muß es sich um einen in C gültigen Datentypen handeln, wobei auch selbstdefinierte vom Typ struct oder union zulässig sind. Der neue Name muß natürlich in Übereinstimmung mit der Namenskonvention für Bezeichner gewählt werden.

Als Beispiele wollen wir hier Ersatznamen vorstellen, die sich bei der MS-Windows- und OS/2-Programmierung mittlerweile für gängige Datentypen eingebürgert haben, wobei die Hersteller von Compilern die entsprechenden typedef-Anweisungen bereits in eigenen Header-Dateien vornehmen:


typedef unsigned char UCHAR;     /* Prefix uc o. uch */
typedef unsigned short USHORT;   /* Prefix us  */
typedef unsigned long ULONG;     /* Prefix ul  */
typedef unsigned int  UINT;      /* Prefix ui  */
typedef unsigned short BOOL;     /* Prefix b   */
typedef unsigned char BYTE;      /* Prefix by  */

Wie diese Auflistung schon vermuten läßt, spricht die verbesserte Lesbarkeit von Programmen für die Verwendung von typedef. Um dieses Ziel zu erreichen, empfiehlt sich jedoch ein besonnener Einsatz dieser Anweisung: Wenn nämlich wegen typedef die Verwendung von Standard-Datentypen zur Ausnahme wird, dann blamiert das Ergebnis die gute Absicht. Wer kann schon die Eigenschaften von zig Datentypen mit Namen wie gehalt oder adresse ständig im Gedächtnis behalten!

Es wird Ihnen vielleicht aufgefallen sein, daß die typedef-Anweisung in Konkurrenz zur Preprozessor-Anweisung #define steht. Beide können gleichermaßen zur Definition neuer Datentypen herangezogen werden. Um beispielsweise einen Datentyp BOOL zum Speichern von Wahrheitswerten einzurichten, stehen Ihnen zwei Möglichkeiten offen:


#define BOOL unsigned short
typedef BOOL unsigned short

Welche der beiden Varianten ist vorzuziehen? Die Entscheidung fällt klar zugunsten von typedef aus. Diese Anweisung ist besser in die Programmiersprache C integriert als #define, das ja nur Ersetzungsvorgänge des Preprozessors bewirkt. Diese bessere Integration macht sich u.a. dadurch bemerkbar, daß Sie mit typedef die Datentypen nur lokal, also innerhalb von Funktionen zur Verfügung stellen können.

Demgegenüber ersetzt der Preprozessor z.B. alle Vorkommnisse von BOOL, sobald ihm diese Konstante bekannt ist und kümmert sich dabei nicht um irgendwelche Gültigkeitsbereiche.

typedef ist zudem flexibler und kann im Gegensatz zu #define gleich bei der Deklaration von Strukturen und Unionen neue Datentypen einführen. Vor allem ist typedef frei von tückischen Nebeneffketen, die bei der Definition von symbolischen Konstanten und Makros sehr leicht auftreten können. Folgendes Beispiel zeigt einen solchen #define-Problemfall:


/* #define-Version für Pointer auf int */
#define  P2INT int *

P2INT piInput, piOutput;

/* typedef-Version */
typedef int * p2int;

p2int piInput, piOutput;

Beide Versionen scheinen die gleiche Aufgabe zu erledigen — nämlich einen neuen Datentyp für int * zu vereinbaren und anschließend zwei Variablen dieses neuen Typs zu definieren. Bei näherem Hinsehen zeigt sich aber, daß die #define-Variante zu einem unbeabsichtigten Nebeneffekt führt, da der Preprozessor die Definition der Variablen folgendermaßen expandiert:


/* nur die 1. Variable ist ein Pointer!! */
int *piInput, piOutput;

Gemeinsam ist beiden Anweisungen, daß sie nicht über das ganze Programm verteilt werden sollten, um die Definitionen neuer Datentypen vorzunehmen. Per Konvention befindet sich der richtige Ort für diesen Zweck am Programmanfang, nach den diversen #include-Anweisungen, aber noch vor main().