Namespaces
Variants

Bit-field

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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