Bit-field
Deklariert ein Klassen-Datenmitglied mit expliziter Größe in Bits. Benachbarte Bitfeld-Mitglieder können (müssen aber nicht) zusammengepackt werden, um einzelne Bytes zu teilen und zu überbrücken.
Eine Bitfeld-Deklaration ist eine Klassen-Datenmitglied-Deklaration , die den folgenden Deklarator verwendet:
Bezeichner
(optional)
attr
(optional)
:
Größe
|
(1) | ||||||||
Bezeichner
(optional)
attr
(optional)
:
Größe
brace-or-equal-initializer
|
(2) | (since C++20) | |||||||
Der Typ des Bitfelds wird durch die decl-specifier-seq der Deklarationssyntax eingeführt.
| attr | - | (since C++11) Folge beliebig vieler attributes |
| identifier | - | Der Name des deklarierten Bitfelds. Der Name ist optional: namenlose Bitfelder führen die angegebene Anzahl von padding bits ein. |
| size | - | Ein integral constant expression mit einem Wert größer oder gleich null. Wenn größer als null, gibt dies die Anzahl der Bits an, die dieses Bitfeld belegen wird. Der Wert null ist nur für namenlose Bitfelder erlaubt und hat besondere Bedeutung . |
| brace-or-equal-initializer | - | default member initializer der mit diesem Bitfeld verwendet werden soll |
Inhaltsverzeichnis |
Erklärung
Der Typ eines Bitfelds kann nur ganzzahlig (einschließlich bool ) oder (möglicherweise cv-qualifizierter) Aufzählungstyp sein, ein unbenanntes Bitfeld kann nicht mit einem cv-qualifizierten Typ deklariert werden.
Ein Bitfeld kann kein static data member sein.
Es gibt keine Bitfeld- Prvalues : Die Lvalue-zu-Rvalue-Konvertierung erzeugt immer ein Objekt des zugrundeliegenden Typs des Bitfelds.
Die Anzahl der Bits in einem Bitfeld legt die Grenze für den Wertebereich fest, den es halten kann:
#include <iostream> struct S { // three-bit unsigned field, allowed values are 0...7 unsigned int b : 3; }; int main() { S s = {6}; ++s.b; // store the value 7 in the bit-field std::cout << s.b << '\n'; ++s.b; // the value 8 does not fit in this bit-field std::cout << s.b << '\n'; // formally implementation-defined, typically 0 }
Mögliche Ausgabe:
7 0
Mehrere benachbarte Bitfelder werden üblicherweise zusammengepackt (obwohl dieses Verhalten implementierungsdefiniert ist):
#include <bit> #include <cstdint> #include <iostream> struct S { // belegt normalerweise 2 Bytes: unsigned char b1 : 3; // erste 3 Bits (im 1. Byte) sind b1 unsigned char : 2; // nächste 2 Bits (im 1. Byte) sind als ungenutzt blockiert unsigned char b2 : 6; // 6 Bits für b2 - passt nicht ins 1. Byte => startet ein 2. Byte unsigned char b3 : 2; // 2 Bits für b3 - nächste (und letzte) Bits im 2. Byte }; int main() { std::cout << sizeof(S) << '\n'; // gibt normalerweise 2 aus S s; // setze unterscheidbare Feldwerte s.b1 = 0b111; s.b2 = 0b101111; s.b3 = 0b11; // zeige Anordnung der Felder in S auto i = std::bit_cast<std::uint16_t>(s); // gibt normalerweise 1110000011110111 aus // Aufschlüsselung: └┬┘├┘└┬┘└─┬──┘└┤ // b1 u a b2 b3 // wobei "u" die ungenutzten :2 im struct markiert und // "a" das vom Compiler hinzugefügte Padding zur Byte-Ausrichtung des nächsten Felds markiert. // Byte-Ausrichtung erfolgt, weil b2 als unsigned char deklariert ist; // wenn b2 als uint16_t deklariert wäre, gäbe es kein "a", b2 würde direkt an "u" anschließen. for (auto b = i; b; b >>= 1) // Ausgabe LSB-first std::cout << (b & 1); std::cout << '\n'; }
Mögliche Ausgabe:
2 1110000011110111
Das spezielle unbenannte Bitfeld der Größe Null kann erzwungen werden, um das Padding aufzubrechen. Es legt fest, dass das nächste Bitfeld am Anfang seiner Zuweisungseinheit beginnt:
#include <iostream> struct S { // belegt normalerweise 2 Bytes: // 3 Bits: Wert von b1 // 5 Bits: ungenutzt // 2 Bits: Wert von b2 // 6 Bits: ungenutzt unsigned char b1 : 3; unsigned char :0; // neues Byte beginnen unsigned char b2 : 2; }; int main() { std::cout << sizeof(S) << '\n'; // gibt normalerweise 2 aus // würde normalerweise 1 ausgeben, wenn nicht // der Padding-Bruch in Zeile 11 }
Mögliche Ausgabe:
2
Wenn die angegebene Größe des Bitfelds größer ist als die Größe seines Typs, wird der Wert durch den Typ begrenzt: ein
std::
uint8_t
b
:
1000
;
würde weiterhin Werte im Bereich
[
0
,
255
]
halten. Die zusätzlichen Bits sind
Auffüllbits
.
Da Bitfelder nicht notwendigerweise am Anfang eines Bytes beginnen, kann die Adresse eines Bitfelds nicht genommen werden. Zeiger und nicht-konstante Referenzen auf Bitfelder sind nicht möglich. Wenn eine const-Referenz initialisiert wird von einem Bitfeld, wird ein temporäres Objekt erstellt (sein Typ ist der Typ des Bitfelds), kopierinitialisiert mit dem Wert des Bitfelds, und die Referenz wird an dieses temporäre Objekt gebunden.
|
Es gibt keine Standard-Member-Initialisierer für Bit-Felder: int b : 1 = 0 ; und int b : 1 { 0 } sind fehlerhaft. |
(bis C++20) |
|
Im Falle einer Mehrdeutigkeit zwischen der Größe des Bit-Felds und dem Standard-Member-Initialisierer wird die längste Sequenz von Tokens gewählt, die eine gültige Größe bildet: int a; const int b = 0; struct S { // einfache Fälle int x1 : 8 = 42; // OK; "= 42" ist Brace-or-Equal-Initializer int x2 : 8 {42}; // OK; "{42}" ist Brace-or-Equal-Initializer // Mehrdeutigkeiten int y1 : true ? 8 : a = 42; // OK; Brace-or-Equal-Initializer ist abwesend int y2 : true ? 8 : b = 42; // Fehler: kann const int nicht zuweisen int y3 : (true ? 8 : b) = 42; // OK; "= 42" ist Brace-or-Equal-Initializer int z : 1 || new int{0}; // OK; Brace-or-Equal-Initializer ist abwesend }; |
(seit C++20) |
Hinweise
Die folgenden Eigenschaften von Bitfeldern sind implementierungsdefiniert :
- Der Wert, der sich aus der Zuweisung oder Initialisierung eines signierten Bitfelds mit einem Wert außerhalb des Bereichs ergibt, oder aus dem Inkrementieren eines signierten Bitfelds über seinen Bereich hinaus.
- Alles bezüglich der tatsächlichen Zuordnungsdetails von Bitfeldern innerhalb des Klassenobjekts.
-
- Beispielsweise überspannen Bitfelder auf einigen Plattformen keine Bytes, auf anderen hingegen schon.
- Ebenso werden Bitfelder auf einigen Plattformen von links nach rechts gepackt, auf anderen von rechts nach links.
In der Programmiersprache C darf die Breite eines Bitfelds die Breite des zugrundeliegenden Typs nicht überschreiten, und es ist implementierungsdefiniert, ob
int
Bitfelder, die nicht explizit als
signed
oder
unsigned
deklariert sind, vorzeichenbehaftet oder vorzeichenlos sind. Zum Beispiel kann
int
b
:
3
;
den Wertebereich
[
0
,
7
]
oder
[
-
4
,
3
]
in C haben, aber in C++ ist nur die letztere Option zulässig.
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrektes Verhalten |
|---|---|---|---|
| CWG 324 | C++98 |
es war nicht spezifiziert, ob der Rückgabewert
einer Zuweisung an ein Bitfeld ein Bitfeld ist |
Bitfeld-Spezifikationen hinzugefügt für
Operatoren, die Lvalues zurückgeben können |
| CWG 739 | C++98 |
Vorzeichenbehaftetheit von Bitfeldern, die weder als
signed noch unsigned deklariert sind, war implementierungsdefiniert |
konsistent mit zugrundeliegenden Typen |
| CWG 2229 | C++98 | unbenannte Bitfelder konnten mit einem cv-qualifizierten Typ deklariert werden | verboten |
| CWG 2511 | C++98 | CV-Qualifizierungen waren in Bitfeld-Typen nicht erlaubt |
Bitfelder können cv-qualifizierte
Aufzählungstypen haben |
Referenzen
- C++23-Standard (ISO/IEC 14882:2024):
-
- 11.4.10 Bit-Felder [class.bit]
- C++20-Standard (ISO/IEC 14882:2020):
-
- 11.4.9 Bit-Felder [class.bit]
- C++17-Standard (ISO/IEC 14882:2017):
-
- 12.2.4 Bit-Felder [class.bit]
- C++14-Standard (ISO/IEC 14882:2014):
-
- 9.6 Bitfelder [class.bit]
- C++11 Standard (ISO/IEC 14882:2011):
-
- 9.6 Bit-Felder [class.bit]
- C++03 Standard (ISO/IEC 14882:2003):
-
- 9.6 Bitfelder [class.bit]
- C++98 Standard (ISO/IEC 14882:1998):
-
- 9.6 Bit-Felder [class.bit]
Siehe auch
|
implementiert Bit-Arrays konstanter Länge
(Klassentemplate) |
|
|
platzsparende dynamische Bitsets
(Klassentemplate-Spezialisierung) |
|
| Bit manipulation (C++20) | Hilfsmittel zum Zugriff, zur Manipulation und Verarbeitung einzelner Bits und Bitsequenzen |
|
C-Dokumentation
für
Bitfelder
|
|