Verwenden von Flags
Einleitung
Dieser Artikel beschreibt eine Programmiertechnik, die in der API-Programmierung unter Windows häufig Verwendung findet. Durch Einsatz der Technik kann einerseits die Lesbarkeit des Quellcodes erhöht, andererseits aber auch der Speicherbedarf der kompilierten Anwendung reduziert werden.
Definition von Flags
Flags können in den meisten Programmiersprachen eingesetzt werden, um Informationen über ausgewählte Eigenschaften oder Optionen, die nur die boolesche Werte wahr und falsch annehmen können, in einem Wert zusammenzufassen, um sie beispielsweise an eine Prozedur zu übergeben. Dazu wird nicht für jede Option ein eigener Parameter vom Datentyp Boolean
vorgesehen, wie man es intuitiv tun würde, sondern nur ein Parameter, meist vom Datentyp Long
.
Betrachtet man das Prinzip genauer, sieht man den Grund für die Bezeichnung Flag (zu Deutsch Flagge). Wie bei einem Schiff können gewisse Flaggen gesetzt sein oder nicht. Der Betrachter sieht nach, welche Flaggen gesetzt sind, und kann so etwa ablesen, ob es bestimmte Krankheiten auf dem Schiff gibt.
Bewertung der Verwendung von Flags
Die Liste zeigt einige Vorteile der im Folgenden an einem Beispiel genauer erläuterten Technik:
Beim Windows-API sind häufig Funktionen zu finden, die nur eine geringe Anzahl an Übergabeparametern aufweisen, aber zulassen, größere Mengen an Informationen zu übergeben. So ist es zum Beispiel möglich, für einen Parameter vom Typ
Long
mehrere Optionskonstanten anzugeben, die dann von der Funktion wieder in ihre Einzelteile zerlegt werden und entsprechende Aktionen auslösen bzw. Optionen einstellen.Es ist nicht sinnvoll, für eine Prozedur mit zwei
Boolean
-Parametern diese Methode zu verwenden, allerdings wird dadurch das Programm auf eine höhere Abstraktionsebene gebracht. Es sollte der Programmierer selbst entscheiden, wann der Einsatz dieser Technik sinnvoll ist.Es sollten Konstanten im Deklarationsabschnitt des Moduls angelegt werden, um die Verständlichkeit der Prozeduraufrufe zu erhöhen, d. h., der Programmierer sollte nicht alle möglichen Konstanten auswendig können müssen, sondern nur im Deklarationsteil die entsprechenden Konstanten suchen. Besonders bietet sich hierzu die Verwendung sogenannter Enumerationen bzw. Aufzählungstypen an, über die mehrere zusammengehörige Konstanten in einen logischen Zusammenhang gebracht werden können.
Häufig werden dadurch Prozeduraufrufe stark verkürzt, weshalb der Code leichter verständlich und besser wartbar wird.
Natürlich hat diese Technik auch Nachteile wie die durch die Bitbreite des Aufzählungsdatentyps beschränkte Anzahl an Optionen, die zusammengefaßt werden können. Allerdings stellt dies in der Praxis selten ein Problem dar, da man meist mit wenigen Optionen auskommt und diese Technik nicht so weit treiben soll, logisch nicht zusammenhängende Dinge zusammenzufassen.
Vergleich anhand eines Beispiels
Folgende Prozedur wäre ungeschickt, da aus dem Prozeduraufruf nicht ersichtlich ist, welche Parameter gewählt wurden, falls die genaue Bedeutung der Parameter der Prozedur nicht bekannt ist. Besonders bei langen Programmen, bei denen der Programmierer nicht die Möglichkeit hat, sofort die Deklarationen der Prozeduren anzusehen (etwa bei der Benutzung von Komponenten, die nicht im Quellcode vorliegen), wird es einem schwer fallen, schnell ein Verständnis für die Funktionsweise des Quellcodes zu erwerben:
Die nachstehende Lösung desselben Problems ist bedeutend einfacher zu verstehen, da bereits am Aufruf der Prozedur erkennbar ist, welche Optionen gewählt wurden. Im Folgenden ist wiederum ein Prozeduraufruf angegeben. Hier erkennt man sofort, daß die Prozedur etwas mit der Formatierung von Text zu tun hat. Außerdem ist nur mehr ein Parameter erforderlich, bei dem die einzelnen Konstanten bitweise durch ein logisches Oder verknüpft werden. Die benötigten Konstanten können in einem Aufzählungstyp zusammengefaßt werden. Der Basistyp von Aufzählungen ist der Datentyp Long
:
Nach welchem Schema die Werte der Konstanten festgelegt werden müssen und wie die Auswertung der gewählten Optionen innerhalb der Implementierung der Prozedur erfolgt, wird im Beispiel im nächsten Abschnitt erklärt.
Ermitteln ausgewählter Optionen
In folgendem Beispiel wird eine Funktion FormatText
implementiert, die den in Text
übergebenen Text entsprechend den in FormatTextFlags
übergebenen Formatierungseigenschaften formatiert. Die Konstanten des Aufzählungstyps FormatTextFlags
enthalten die Werte für die angebotenen Optionen.
Entscheidend bei der Wahl der Werte der Optionskonstanten ist, daß sich der Wert von Konstante zu Konstante immer verdoppelt. Nur so kann innerhalb der Prozedur, an welche die zusammengefaßten Werte übergeben werden, erkennen, welche Optionen ausgewählt wurden. Die Verdopplung des Wertes entspricht der Bildung von Zweierpotenzen, bei deren Darstellung im Rechner dann immer genau ein Bit gesetzt wird. In einem vereinfachten Modell (hier verwenden wir nur acht Bit und unterscheiden nicht zwischen negativen und positiven Zahlen) kann man sich das wie folgt vorstellen:
Basis | Exponent | Dezimale Entsprechung | Darstellung im Computer |
---|---|---|---|
2 | 0 | 1 | 00000001 |
2 | 1 | 2 | 00000010 |
2 | 2 | 4 | 00000100 |
2 | 3 | 8 | 00001000 |
… | … | … | … |
Wie man leicht erkennen kann, ist es mit den 32 Bits des Datentyps Long
möglich, bis zu 32 Wahrheitswerte zu repräsentieren. Durch das „Verodern“ der Konstanten werden dann die entsprechenden Bits gesetzt, also 0000010
Oder-verknüpft mit 0010000
ergibt 00100010
.
Um in der Prozedur, hier FormatText
, zu prüfen, ob eine bestimmte Option gewählt wurde, wird geprüft, ob das entsprechende Bit der Optionskonstante in dem in Format
übergebenen Wert enthalten ist. Dazu wird folgender Code verwendet:
Dabei erfolgt eine bitweise Und-Verknüpfung. Ist das Ergebnis gleich null, dann ist die Option nicht gewählt, andernfalls schon. Man könnte anstelle des Vergleichs mit der Optionskonstante zur Überprüfung auf Auswahl der Option auch einen Vergleich auf Ungleichheit zu null durchführen. Auf diese Weise kann jede Option abgefragt und eine entsprechende Aktion ausgeführt werden. Zum Aufruf von FormatText
mit mehreren Optionen werden im Parameter Format
alle gewünschten Optionen durch ein bitweises Oder verknüpft:
Schlußwort
Durch Verwendung von Flags können Komplexität und Umfang von Prozeduren erheblich reduziert werden. Flags sind dann geeignet, wenn sich die Schnittstelle der Prozedur bei Hinzufügen neuer Optionsparameter nicht ändern soll. Würde man für jede Option einen eigenen Parameter vom Datentyp Boolean
vorsehen, würde die Erweiterung um eine neue Option ein Umschreiben des Codes erforderlich machen.