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 | ||||||||||||||||
| ||||||||||||||||
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 | ||||||||||||||||
Declares a class data member with explicit size, in bits. Adjacent bit-field members may (or may not) be packed to share and straddle the individual bytes.
A bit-field declaration is aclass data member declaration which uses the following declarator:
identifier (optional)attr (optional): size | (1) | ||||||||
identifier (optional)attr (optional): sizebrace-or-equal-initializer | (2) | (since C++20) | |||||||
Thetype of the bit-field is introduced by thedecl-specifier-seq of thedeclaration syntax.
attr | - | (since C++11) sequence of any number ofattributes |
identifier | - | the name of the bit-field that is being declared. The name is optional: unnamed bit-fields introduce the specified number ofpadding bits. |
size | - | anintegral 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 bit-fields and hasspecial meaning. |
brace-or-equal-initializer | - | default member initializer to be used with this bit-field |
Contents |
The type of a bit-field can only be integral (includingbool) or (possibly cv-qualified) enumeration type, an unnamed bit-field cannot be declared with a cv-qualified type.
A bit-field cannot be astatic data member.
There are no bit-fieldprvalues: 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...7unsignedint b:3;}; int main(){ S s={6}; ++s.b;// store the value 7 in the bit-fieldstd::cout<< s.b<<'\n'; ++s.b;// the value 8 does not fit in this bit-fieldstd::cout<< s.b<<'\n';// formally implementation-defined, typically 0}
Possible output:
70
Multiple adjacent bit-fields are usually packed together (although this behavior is implementation-defined):
#include <bit>#include <cstdint>#include <iostream> struct S{// will usually occupy 2 bytes:unsignedchar b1:3;// 1st 3 bits (in 1st byte) are b1unsignedchar:2;// next 2 bits (in 1st byte) are blocked out as unusedunsignedchar b2:6;// 6 bits for b2 - doesn't fit into the 1st byte => starts a 2ndunsignedchar 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 Sauto 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-firststd::cout<<(b&1);std::cout<<'\n';}
Possible output:
21110000011110111
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// 2 bits: value of b2// 6 bits: unusedunsignedchar b1:3;unsignedchar:0;// start a new byteunsignedchar 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}
Possible output:
2
If the specified size of the bit-field is greater than the size of its type, the value is limited by the type: astd::uint8_t b:1000; would still hold values in the range[
0,
255]
. The extra bits arepadding bits.
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. Wheninitializing 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 nodefault member initializers for bit-fields:int b:1=0; andint 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;constint b=0; struct S{// simple casesint x1:8=42;// OK; "= 42" is brace-or-equal-initializerint x2:8{42};// OK; "{42}" is brace-or-equal-initializer // ambiguitiesint y1:true?8: a=42;// OK; brace-or-equal-initializer is absentint y2:true?8: b=42;// error: cannot assign to const intint y3:(true?8: b)=42;// OK; "= 42" is brace-or-equal-initializerint z:1|| newint{0};// OK; brace-or-equal-initializer is absent}; | (since C++20) |
The following properties of bit-fields areimplementation-defined:
In the C programming language, the width of a bit-field cannot exceed the width of the underlying type, and whetherint bit-fields that are not explicitlysigned orunsigned 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++.
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 324 | C++98 | it was unspecified whether the return value of an assignment to a bit-field is a bit-field | added bit-field specifications for operators which may return lvalues |
CWG 739 | C++98 | signedness of bit-fields that are neither declared signed norunsigned were implementation-defined | consistent with underlying types |
CWG 2229 | C++98 | unnamed bit-fields could be declared with a cv-qualified type | prohibited |
CWG 2511 | C++98 | cv-qualifications were not allowed in bit-field types | bit-fields can have cv-qualified enumeration types |
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 forBit-fields |