Skip to content

Last updated:2026-10-12

C++ Bit Fields

About the Author

WeChat official account:

wechat

What Is a Bit Field?

A "bit field" (or "bit segment") is a data structure that can store data compactly in bit form and allows the programmer to operate on the bits of the structure. One benefit of this data structure is that it saves storage space for each data unit; when a program needs thousands of data units, this approach becomes especially important. A second benefit is that bit fields make it easy to access part of the content of an integer value, which simplifies the program source code. The drawback of this data structure is that bit field implementations depend on the specific machine and system, and different platforms may produce different results, which makes bit fields inherently non-portable.

  • The in-memory layout of bit fields is machine-dependent
  • The type of a bit field must be an integral or enumeration type; the behavior of bit fields within signed types is implementation-defined
  • The address-of operator (&) cannot be applied to a bit field; no pointer can point to a bit field of a class

Using Bit Fields

Bit fields are usually declared with a struct. The struct declaration gives each bit field member a name and determines its width:

struct bit_field_name
{
    type member_name : width;
};
Elements Description
bit_field_name Name of the bit field struct
type Type of the bit field member; must be int, signed int, or unsigned int
member_name Name of the bit field member
width The number of bits occupied by the member

For example, declare the following bit field:

struct _PRCODE
{
    unsigned int code1: 2;
    unsigned int cdde2: 2;
    unsigned int code3: 8;
};
struct _PRCODE prcode;

This definition makes prcode contain two 2-bit bit fields and one 8-bit bit field. We can assign to them using the struct member operator:

prcode.code1 = 0;
prcode.code2 = 3;
procde.code3 = 102;

Note that when assigning, the value must not exceed the capacity of the bit field member. For example, prcode.code3 is an 8-bit bit field member whose capacity is 2^8 = 256, that is, the assignable range is [0,255].

Size and Alignment of Bit Fields

Size of a Bit Field

For example, the following bit field:

struct box 
{
    unsigned int a: 1;
    unsigned int  : 3;
    unsigned int b: 4;
};

There is an unnamed bit field in the middle of this bit field struct, occupying 3 bits, which serves only as padding and has no actual meaning. The padding makes the structure use 8 bits in total. But the C language uses unsigned int as the basic unit for bit fields, so even if the only member of a structure is a 1-bit bit field, the structure's size is the same as an unsigned int. On some systems unsigned int is 16 bits; on x86 systems it is 32 bits. The rest of this article assumes unsigned int is 32 bits.

Alignment of Bit Fields

A bit field member is not allowed to straddle the boundary of two unsigned ints. If the total number of bits declared for the members exceeds the size of one unsigned int, the compiler automatically shifts the bit field members so that they align to unsigned int boundaries. For example:

struct stuff 
{
    unsigned int field1: 30;
    unsigned int field2: 4;
    unsigned int field3: 3;
};

field1 + field2 = 34 bits, which exceeds 32 bits. The compiler moves field2 into the next unsigned int unit for storage, leaving a 2-bit gap between stuff.field1 and stuff.field2; stuff.field3 immediately follows stuff.field2, so the structure is now 2 * 32 = 64 bits in size.

This hole can be filled with the unnamed bit field member mentioned earlier; we can also use an unnamed bit field member of width 0 to force the next bit field member to align with the next integer. For example:

struct stuff 
{
    unsigned int field1: 30;
    unsigned int       : 2;
    unsigned int field2: 4;
    unsigned int       : 0;
    unsigned int field3: 3; 
};

Here there is a 2-bit gap between stuff.field1 and stuff.field2, while stuff.field3 is stored in the next unsigned int, so the structure is now 3 * 32 = 96 bits in size.

For the accompanying code see: bit.cpp

Initialization and Re-mapping of Bit Fields

Initialization

Bit fields are initialized the same way as ordinary structs. Two ways are listed here:

struct stuff s1= {20,8,6};

Or assign values to the bit field members directly:

struct stuff s1;
s1.field1 = 20;
s1.field2 = 8;
s1.field3 = 4;

Re-mapping of Bit Fields (Re-mapping)

Declare a bit field with a size of 32 bits:

struct box {
    unsigned int ready:     2;
    unsigned int error:     2;
    unsigned int command:   4;
    unsigned int sector_no: 24;
}b1;

Zeroing a bit field via re-mapping

int* p = (int *) &b1;  // 将 "位域结构体的地址" 映射至 "整形(int*) 的地址" 
*p = 0;                // 清除 s1,将各成员归零

Re-mapping a 32-bit bit field to unsigned int via a union (union)

First, a brief introduction to unions:

A "union" is a special kind of class and also a constructed data-structure type. Within a "union" you can define several different data types. A variable declared as being of this "union" type allows any of the data types defined by the "union" to be stored in it; these data share the same stretch of memory in order to save space.

A "union" has some similarities to a "struct", but the two are fundamentally different. In a struct, each member has its own memory space, and the total length of a struct variable is the sum of its members' lengths (empty structs excepted, and ignoring boundary adjustment). In a "union", the members share a stretch of memory, and the length of a union variable equals the length of its longest member. It should be made clear that this "sharing" does not mean loading multiple members into a union variable at the same time; it means the union variable may be assigned the value of any member, but only one value at a time — assigning a new value overwrites the old one.

We can declare the following union:

union u_box {
  struct box st_box;     
  unsigned int ui_box;
};

On x86 systems both unsigned int and box are 32 bits; through this union, st_box and ui_box share the same block of memory. Exactly which bit of the unsigned int corresponds to which bit of the bit field depends on the compiler and the hardware. To zero the bit field using the union, the code is as follows:

union u_box u;
u.ui_box = 0;

Learning reference: http://www.yuan-ji.me/C-C-%E4%BD%8D%E5%9F%9F-Bit-fields-%E5%AD%A6%E4%B9%A0%E5%BF%83%E5%BE%97/

Comments