HOWTO · Csharp
Bitmaske in C# verwenden
In diesem Artikel erfahren Sie, wie Sie Bitmasken in C# verwenden.
Auf dieser Seite
Eine Bitmaske ist eine Ganzzahl, deren einzelne Bits unabhängige Flags darstellen. Ein Berechtigungswert kann zum Beispiel Lese-, Schreib- und Ausführungsrechte in einer einzigen Zahl speichern. Mit den bitweisen Operatoren von C# können Sie diese Bits prüfen, auslesen, setzen, löschen, umschalten, invertieren und verschieben. Verwenden Sie benannte Masken, damit bei jeder Operation klar ist, welches Flag betroffen ist.
Bitmasken und bitweise Operatoren verstehen
Jedes Bit hat den Wert 0 oder 1. Die Operatoren vergleichen die jeweils entsprechenden Bits: AND (&) ergibt nur dann 1, wenn beide Eingaben 1 sind; OR (|) ergibt 1, wenn mindestens eine Eingabe 1 ist; XOR (^) ergibt 1, wenn sich die Eingaben unterscheiden; und NOT (~) kehrt jedes Bit seines ganzzahligen Operanden um. Die Schiebeoperatoren (<< und >>) verschieben Bits um eine angegebene Anzahl von Positionen.
| Operation | Bedeutung für jedes Bit |
|---|---|
x & y |
Behält ein Bit nur bei, wenn es in beiden Werten gesetzt ist. |
| `x | y` |
x ^ y |
Setzt ein Bit, wenn es genau in einem der beiden Werte gesetzt ist. |
~x |
Kehrt jedes Bit der ganzzahligen Darstellung um. |
Eine Maske ist ein Wert, der an den interessierenden Positionen 1 und an allen anderen Positionen 0 enthält. Verwenden Sie vorzugsweise benannte Konstanten wie Read = 1 und Write = 2; diese Werte wählen unterschiedliche Bitpositionen aus.
Bits mit & prüfen und auslesen
Um ein Flag zu prüfen, verknüpfen Sie den Wert mit seiner Maske per AND. Das Flag ist gesetzt, wenn das Ergebnis ungleich null ist: if ((permissions & Read) != 0). Das funktioniert, weil die Maske alle anderen Positionen auf null setzt. Um mehrere ausgewählte Bits auszulesen, verwenden Sie eine Maske, die diese Positionen enthält; das Ergebnis behält nur die ausgewählten Bits bei. Zum Beispiel liest permissions & (Read | Write) die Lese- und Schreib-Flags gemeinsam aus.
Bits mit | setzen
Verknüpfen Sie einen Wert per OR mit einer Flag-Maske, um die betreffenden Bits einzuschalten und die übrigen Bits beizubehalten. Die zusammengesetzte Zuweisung permissions |= Write ist eine Kurzform dafür, permissions | Write wieder permissions zuzuweisen. Ein bereits gesetztes Flag bleibt gesetzt. Diese Operation eignet sich daher, wenn sichergestellt werden soll, dass ein Flag aktiviert ist.
Bits mit ^ umschalten
XOR mit einer Maske kehrt nur die Positionen um, an denen die Maske eine 1 enthält: permissions ^= Execute. Ein gesetztes Bit wird gelöscht, ein gelöschtes Bit wird gesetzt. Das eignet sich für ein bewusstes Umschalten, ist aber keine idempotente Methode, um ein Flag sicher einzuschalten: Bei zweimaliger Anwendung wird der ursprüngliche Wert wiederhergestellt.
Bits mit ~ invertieren
NOT kehrt alle Bits des ganzzahligen Typs um, auch solche, die nicht zu den Flags Ihrer Anwendung gehören. Um ein bekanntes Flag zu löschen, kombinieren Sie AND mit der invertierten Maske: permissions &= ~Write. Die übrigen Flag-Positionen bleiben unverändert. Wenn Sie einen invertierten Wert als Bitfolge fester Breite anzeigen möchten, begrenzen Sie ihn zuvor mit einer Maske auf diese Breite. Das numerische Ergebnis von ~value ist selbst nicht auf die sichtbaren Flags beschränkt.
Bits mit << und >> verschieben
Eine Linksverschiebung bewegt Bits zu höheren Positionen. Bei nicht negativen Werten, deren verschobenes Ergebnis in den Typ passt, wirkt value << count wie eine Multiplikation mit einer Zweierpotenz. Eine Rechtsverschiebung bewegt Bits zu niedrigeren Positionen; bei nicht negativen Werten verwirft sie die niedrigsten verschobenen Bits. Bei negativen vorzeichenbehafteten Werten bleibt beim Rechtsshift von C# das Vorzeichenbit erhalten. Beschreiben Sie daher nicht jede Rechtsverschiebung so, als würden dabei Nullen eingefügt. Wenn Sie eine logische Rechtsverschiebung benötigen, verwenden Sie einen vorzeichenlosen Typ und wählen Sie eine für den Ganzzahltyp passende Anzahl an Schiebeschritten.
Mit Verschiebungen lassen sich außerdem kompakt Masken erstellen: 1 << 0, 1 << 1 und 1 << 2 wählen bei kleinen nicht negativen Schiebewerten aufeinanderfolgende Bitpositionen aus. Benannte Konstanten sind im Anwendungscode meist leichter lesbar.
Flags in einem praktischen Beispiel kombinieren
Dieses Programm beginnt ohne Berechtigungen, aktiviert Lese- und Schreibzugriff, prüft und liest diese Flags aus, löscht anschließend das Schreib-Flag und schaltet danach das Ausführungs-Flag um. Jeder ausgegebene Wert beschreibt den Zustand nach der jeweiligen Operation. Das Beispiel enthält einen vollständigen Main-Einstiegspunkt und verwendet dezimale Masken.
Führen Sie dieses Beispiel aus:
Der unveränderliche Codeblock und seine Bezeichnungen oder Ausgaben bleiben auf Englisch.
using System;
class Program
{
static void Main()
{
const int Read = 1;
const int Write = 2;
const int Execute = 4;
int permissions = 0;
permissions |= Read | Write;
Console.WriteLine((permissions & Read) != 0);
Console.WriteLine(permissions & (Read | Write));
permissions &= ~Write;
permissions ^= Execute;
Console.WriteLine(permissions);
}
}
Die erste Operation setzt mit OR zwei Flags. Die Prüfung gibt aus, ob Read gesetzt ist; beim Auslesen werden die ausgewählten Bits als Zahl ausgegeben. Das Löschen mit &= ~Write entfernt nur das Schreib-Bit; anschließend schaltet XOR das Ausführungs-Flag um. Verwenden Sie für Masken und gespeicherte Werte kompatible Ganzzahltypen und benannte Flags, damit die vorgesehenen Positionen klar erkennbar sind.