Bit field

< cpp‎ | language
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
range-for (C++11)
Jump statements
Function declaration
Lambda function declaration
inline specifier
Dynamic exception specifications (until C++20)
noexcept specifier (C++11)
decltype (C++11)
auto (C++11)
alignas (C++11)
Storage duration specifiers
Alternative representations
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Attributes (C++11)
typedef declaration
Type alias declaration (C++11)
Implicit conversions - Explicit conversions
static_cast - dynamic_cast
const_cast - reinterpret_cast
Memory allocation
Class-specific function properties
explicit (C++11)
Special member functions

Declares a class data member with explicit size, in bits. Adjacent bit field members may be packed to share and straddle the individual bytes.

A bit field declaration is a class data member declaration which uses the following declarator:

identifier(optional) attr(optional) : size (1)
identifier(optional) attr(optional) : size brace-or-equal-initializer (2) (since C++20)

The type of the bit field is introduced by the decl-specifier-seq of the declaration syntax.

attr - (since C++11) optional sequence of any number of attributes
identifier - the name of the bit field that is being declared. The name is optional: nameless bitfields introduce the specified number of bits of padding
size - an integral constant expression with a value greater or equal to zero. When greater than zero, this is the number of bits that this bit field will occupy. The value zero is only allowed for nameless bitfields and has special meaning: it specifies that the next bit field in the class definition will begin at an allocation unit's boundary.
brace-or-equal-initializer - default member initializer to be used with this bit field


[edit] Explanation

The type of a bit field can only be integral or enumeration type.

A bit field cannot be a static data member.

There are no bit field prvalues: lvalue-to-rvalue conversion always produces an object of the underlying type of the bit field.

The number of bits in a bit field sets the limit to the range of values it can hold:

#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

Possible output:


Multiple adjacent bit fields are usually packed together (although this behavior is implementation-defined):

#include <iostream>
struct S {
    // will usually occupy 2 bytes:
    // 3 bits: value of b1
    // 2 bits: unused
    // 6 bits: value of b2
    // 2 bits: value of b3
    // 3 bits: unused
    unsigned char b1 : 3, : 2, b2 : 6, b3 : 2;
int main()
    std::cout << sizeof(S) << '\n'; // usually prints 2

Possible output:


The special unnamed bit field of size zero can be forced to break up padding. It specifies that the next bit field begins at the beginning of its allocation unit:

#include <iostream>
struct S {
    // will usually occupy 2 bytes:
    // 3 bits: value of b1
    // 5 bits: unused
    // 6 bits: value of b2
    // 2 bits: value of b3
    unsigned char b1 : 3;
    unsigned char :0; // start a new byte
    unsigned char b2 : 6;
    unsigned char b3 : 2;
int main()
    std::cout << sizeof(S) << '\n'; // usually prints 2

Possible output:


If the specified size of the bit field is greater than the size of its type, the value is limited by the type: a std::uint8_t b : 1000; would still hold values between 0 and 255. the extra bits become unused padding.

Because bit fields do not necessarily begin at the beginning of a byte, address of a bit field cannot be taken. Pointers and non-const references to bit fields are not possible. When initializing a const reference from a bit field, a temporary is created (its type is the type of the bit field), copy initialized with the value of the bit field, and the reference is bound to that temporary.

There are no default member initializers for bit fields: int b : 1 = 0; and int b : 1 {0} are ill-formed.

(until C++20)

In case of ambiguity between the size of the bit field and the default member initializer, the longest sequence of tokens that forms a valid size is chosen:

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
(since C++20)

[edit] Notes

The following properties of bit fields are implementation-defined:

  • The value that results from assigning or initializing a signed bit field with a value out of range, or from incrementing a signed bit field past its range.
  • Everything about the actual allocation details of bit fields within the class object
  • For example, on some platforms, bit fields don't straddle bytes, on others they do
  • Also, on some platforms, bit fields are packed left-to-right, on others right-to-left

In the C programming language, the width of a bit field cannot exceed the width of the underlying type, and whether int bit fields that are not explicitly signed or unsigned are signed or unsigned is implementation-defined. For example, int b:3; may have the range of values 0..7 or -4..3 in C, but only the latter choice is allowed in C++.

[edit] Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
CWG 739 C++98 signedness of bit fields that aren't signed or unsigned were implementation-defined consistent with underlying types

[edit] References

  • C++20 standard (ISO/IEC 14882:2020):
  • 11.4.9 Bit-fields [class.bit]
  • C++17 standard (ISO/IEC 14882:2017):
  • 12.2.4 Bit-fields [class.bit]
  • C++14 standard (ISO/IEC 14882:2014):
  • 9.6 Bit-fields [class.bit]
  • C++11 standard (ISO/IEC 14882:2011):
  • 9.6 Bit-fields [class.bit]
  • C++03 standard (ISO/IEC 14882:2003):
  • 9.6 Bit-fields [class.bit]
  • C++98 standard (ISO/IEC 14882:1998):
  • 9.6 Bit-fields [class.bit]

[edit] See also

implements constant length bit array
(class template) [edit]
space-efficient dynamic bitset
(class template specialization) [edit]
Bit manipulation (C++20) utilities to access, manipulate, and process individual bits and bit sequences
C documentation for Bit fields