Namensräume
Varianten
Aktionen

Bitfeld

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
 

Deklariert ein Klassen-Datenelement mit expliziter Größe in Bits. Benachbarte Bit-Felder können (müssen aber nicht) gepackt werden, um einzelne Bytes gemeinsam zu nutzen und zu durchtrennen.

Eine Bit-Feld-Deklaration ist eine Klassen-Datenelement-Deklaration, die den folgenden Deklarator verwendet

Bezeichner (optional) attr (optional) : Größe (1)
Bezeichner (optional) attr (optional) : Größe Klammer-oder-Gleichheits-Initialisierer (2) (seit C++20)

Der Typ des Bit-Felds wird durch die decl-specifier-seq der Deklarationssyntax eingeführt.

attr - (seit C++11) Sequenz einer beliebigen Anzahl von Attributen
identifier - der Name des zu deklarierenden Bit-Felds. Der Name ist optional: Namenslose Bit-Felder führen die angegebene Anzahl von Auffüllbits ein.
size - ein ganzzahliger konstanter Ausdruck mit einem Wert größer oder gleich Null. Wenn größer als Null, ist dies die Anzahl der Bits, die dieses Bit-Feld belegen wird. Der Wert Null ist nur für namenlose Bit-Felder zulässig und hat eine besondere Bedeutung.
Klammer-oder-Gleichheits-Initialisierer - Standard-Member-Initialisierer, der mit diesem Bit-Feld verwendet werden soll

Inhalt

[bearbeiten] Erklärung

Der Typ eines Bit-Felds kann nur ein ganzzahliger Typ (einschließlich bool) oder ein (möglicherweise cv-qualifizierter) Aufzählungstyp sein. Ein namenloses Bit-Feld kann nicht mit einem cv-qualifizierten Typ deklariert werden.

Ein Bit-Feld kann kein statisches Datenelement sein.

Es gibt keine Bit-Feld-prvalues: Die Umwandlung von lvalues in rvalues erzeugt immer ein Objekt des zugrunde liegenden Typs des Bit-Felds.

Die Anzahl der Bits in einem Bit-Feld begrenzt den Wertebereich, den es speichern 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 Bit-Felder werden normalerweise zusammengepackt (obwohl dieses Verhalten implementierungsabhängig ist)

#include <bit>
#include <cstdint>
#include <iostream>
 
struct S
{
    // will usually occupy 2 bytes:
    unsigned char b1 : 3; // 1st 3 bits (in 1st byte) are b1
    unsigned char    : 2; // next 2 bits (in 1st byte) are blocked out as unused
    unsigned char b2 : 6; // 6 bits for b2 - doesn't fit into the 1st byte => starts a 2nd
    unsigned char b3 : 2; // 2 bits for b3 - next (and final) bits in the 2nd byte
};
 
int main()
{
    std::cout << sizeof(S) << '\n'; // usually prints 2
 
    S s;
    // set distinguishable field values
    s.b1 = 0b111;
    s.b2 = 0b101111;
    s.b3 = 0b11;
 
    // show layout of fields in S
    auto i = std::bit_cast<std::uint16_t>(s);
    // usually prints 1110000011110111
    // breakdown is:  └┬┘├┘└┬┘└─┬──┘└┤
    //                b1 u  a   b2  b3
    // where “u” marks the unused :2 specified in the struct, and
    // “a” marks compiler-added padding to byte-align the next field.
    // Byte-alignment is happening because b2's type is declared unsigned char;
    // if b2 were declared uint16_t there would be no “a”, b2 would abut “u”.
    for (auto b = i; b; b >>= 1) // print LSB-first
        std::cout << (b & 1);
    std::cout << '\n';
}

Mögliche Ausgabe

2
1110000011110111

Das spezielle namenlose Bit-Feld der Größe Null kann verwendet werden, um Auffüllungen zu erzwingen. Es gibt an, dass das nächste Bit-Feld am Anfang seiner Alloziationseinheit beginnt.

#include <iostream>
 
struct S
{
    // will usually occupy 2 bytes:
    // 3 bits: value of b1
    // 5 bits: unused
    // 2 bits: value of b2
    // 6 bits: unused
    unsigned char b1 : 3;
    unsigned char :0; // start a new byte
    unsigned char b2 : 2;
};
 
int main()
{
    std::cout << sizeof(S) << '\n'; // usually prints 2
                                    // would usually print 1 if not for
                                    // the padding break in line 11
}

Mögliche Ausgabe

2

Wenn die angegebene Größe des Bit-Felds größer ist als die Größe seines Typs, wird der Wert durch den Typ begrenzt: ein std::uint8_t b : 1000; speichert immer noch Werte im Bereich [0255]. Die zusätzlichen Bits sind Auffüllbits.

Da Bit-Felder nicht notwendigerweise am Anfang eines Bytes beginnen, kann die Adresse eines Bit-Felds nicht genommen werden. Zeiger und nicht-const Referenzen auf Bit-Felder sind nicht möglich. Beim Initialisieren einer const-Referenz aus einem Bit-Feld wird ein temporäres Objekt erstellt (dessen Typ der Typ des Bit-Felds ist), mit dem Wert des Bit-Felds kopierinitialisiert und die Referenz 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 Token gewählt, die eine gültige Größe bildet.

int a;
const int b = 0;
 
struct S
{
    // simple cases
    int x1 : 8 = 42; // OK; "= 42" is brace-or-equal-initializer
    int x2 : 8 {42}; // OK; "{42}" is brace-or-equal-initializer
 
    // ambiguities
    int y1 : true ? 8 : a = 42;   // OK; brace-or-equal-initializer is absent
    int y2 : true ? 8 : b = 42;   // error: cannot assign to const int
    int y3 : (true ? 8 : b) = 42; // OK; "= 42" is brace-or-equal-initializer
    int z : 1 || new int{0};      // OK; brace-or-equal-initializer is absent
};
(seit C++20)

[bearbeiten] Hinweise

Die folgenden Eigenschaften von Bit-Feldern sind implementierungsabhängig

  • Der Wert, der sich aus der Zuweisung oder Initialisierung eines vorzeichenbehafteten Bit-Felds mit einem Wert außerhalb seines Bereichs ergibt, oder aus der Inkrementierung eines vorzeichenbehafteten Bit-Felds über seinen Bereich hinaus.
  • Alles über die tatsächlichen Alloziationsdetails von Bit-Feldern innerhalb des Klassenobjekts.
  • Zum Beispiel, auf einigen Plattformen durchdringen Bit-Felder keine Bytes, auf anderen schon.
  • Ebenso werden auf einigen Plattformen Bit-Felder von links nach rechts, auf anderen von rechts nach links gepackt.

In der Programmiersprache C darf die Breite eines Bit-Felds nicht die Breite des zugrunde liegenden Typs überschreiten, und ob int Bit-Felder, die nicht explizit signed oder unsigned sind, vorzeichenbehaftet oder vorzeichenlos sind, ist implementierungsabhängig. Zum Beispiel, int b : 3; kann den Wertebereich [07] oder [-43] in C haben, aber nur die letztere Wahl ist in C++ erlaubt.

[bearbeiten] Fehlerberichte

Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
CWG 324 C++98 es war nicht spezifiziert, ob der Rückgabewert
einer Zuweisung zu einem Bit-Feld ein Bit-Feld ist
Bit-Feld-Spezifikationen für
Operatoren, die lvalues zurückgeben können
CWG 739 C++98 Vorzeichenbehaftung von Bit-Feldern, die weder deklariert sind
signed noch unsigned waren implementierungsabhängig
konsistent mit den zugrunde liegenden Typen
CWG 2229 C++98 namenlose Bit-Felder konnten mit einem cv-qualifizierten Typ deklariert werden verboten
CWG 2511 C++98 cv-Qualifizierungen waren in Bit-Feld-Typen nicht erlaubt Bit-Felder können cv-qualifiziert sein
Aufzählungstypen

[bearbeiten] 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 Bit-Felder [class.bit]
  • C++11 Standard (ISO/IEC 14882:2011)
  • 9.6 Bit-Felder [class.bit]
  • C++03-Standard (ISO/IEC 14882:2003)
  • 9.6 Bit-Felder [class.bit]
  • C++98 Standard (ISO/IEC 14882:1998)
  • 9.6 Bit-Felder [class.bit]

[bearbeiten] Siehe auch

implementiert eine Bit-Array fester Länge
(Klassenvorlage) [edit]
speichereffizientes dynamisches Bitset
(class template specialization) [edit]
Bit-Manipulation (C++20) Dienstprogramme zum Zugreifen, Bearbeiten und Verarbeiten einzelner Bits und Bitsequenzen
C-Dokumentation für Bit-Felder