Die rotär (circular) Shift-Operation ist eine Verschiebung der Bits einer Zahl um eine bestimmte Anzahl von Stellen, wobei die "ausgefallenen" Bits an das andere Ende verschoben werden. In der Programmiersprache C gibt es keinen eingebauten Operator für diese Aufgabe; diese Entscheidung ist historisch bedingt und hängt mit der Portabilität der Standardbibliothek sowie der Notwendigkeit zusammen, das Verhalten für verschiedene Plattformen eindeutig zu definieren.
Das Problem besteht darin, dass die Standardverschiebeoperatoren (<<, >>) keine rotäre Verschiebung durchführen: Sie verschieben lediglich die Bits und ersetzen die "ausgefallenen" Bits durch Nullen. Für eine rotäre Verschiebung müssen die Ergebnisse von zwei Verschiebungen explizit kombiniert und das Ergebnis mit einer bestimmten Anzahl von Bits maskiert werden.
Die Lösung besteht darin, die rotäre Verschiebung manuell zu implementieren. Für eine 32-Bit unsigned Zahl sieht das so aus:
uint32_t rotate_left(uint32_t value, unsigned int shift) { return (value << shift) | (value >> (32 - shift)); } uint32_t rotate_right(uint32_t value, unsigned int shift) { return (value >> shift) | (value << (32 - shift)); }
Wichtige Merkmale:
Kann der Operator << oder >> eine rotäre Verschiebung ohne zusätzliche Operationen durchführen?
Nein. Normale Verschiebungen ersetzen die aus dem Rahmen gefallenen Bits durch Nullen und verschieben sie nicht an die andere Seite.
Was passiert, wenn Sie eine Verschiebung in der Größe des Typs (shift ist gleich der Anzahl der Bits in der Zahl) durchführen?
Das Verhalten ist nicht definiert (Undefined Behavior gemäß dem C-Standard), es ist unbedingt erforderlich, die Verschiebung modulo der Größe des Typs durchzuführen.
Ist es sicher, diesen Funktionen für signed Typen eine rotäre Verschiebung zu geben?
Nein, verwenden Sie immer unsigned Typen, da bitweise Verschiebungen für signed Typen je nach Compiler und Architektur unterschiedlich funktionieren.
Verwendung einer normalen Verschiebung für eine rotäre Verschiebung:
uint32_t x = 0xFA3C0F00; uint32_t y = x << 5; // Hat keinen rotarischen Charakter
Vorteile:
Nachteile:
Verwendung einer manuellen rotären Shift-Funktion unter Berücksichtigung der Typgröße und Schutz vor UB:
uint32_t x = 0xFA3C0F00; uint32_t y = rotate_left(x, 5);
Vorteile:
Nachteile: