Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A bit-field is a class of structure or union member in C that specifies the exact number of bits used for its storage. It enables fine-grained control over memory layout by packing multiple variables into a single machine word or addressable storage unit.

Syntax

A bit-field is declared inside a struct or union using a colon followed by an integer constant expression representing the bit width.
struct StructName {
    type member_name : width;
};
struct BitFieldExample {
    unsigned int flag_a : 1;  // Occupies exactly 1 bit
    unsigned int flag_b : 3;  // Occupies exactly 3 bits
    signed int   value  : 4;  // Occupies exactly 4 bits
};

Type Requirements and Value Ranges

The C Standard dictates that a bit-field must have a qualified or unqualified version of one of the following types:
  • _Bool (since C99)
  • signed int
  • unsigned int
If declared as plain int, whether the high-order bit is treated as a sign bit or part of the value is implementation-defined. Since C99, the standard explicitly permits “some other implementation-defined type” (C11 6.7.2.1p5). Therefore, using types like char, short, long, or uint8_t is standard-compliant (though implementation-defined), not a non-standard compiler extension. Value Ranges: The range of values a bit-field can hold depends on its width NN and its signedness.
  • An unsigned bit-field of width NN has a range of 00 to 2N12^N - 1.
  • A signed bit-field of width NN (assuming two’s complement) has a range of 2N1-2^{N-1} to 2N112^{N-1} - 1.
A critical pitfall occurs with 1-bit signed bit-fields (signed int x : 1;). Because one bit is used for the sign, its value range is strictly 0 to -1. It cannot hold the value 1.

Integer Promotion Rules

Bit-fields are subject to standard C integer promotion rules. If a bit-field of type unsigned int has a width strictly less than the width of a standard int, and a standard int can represent all possible values of that bit-field, the bit-field is promoted to signed int in expressions. This semantic rule frequently causes bugs during bitwise operations or comparisons, as the implicitly promoted signed int may undergo unexpected sign-extension if further operations cause it to be cast or promoted to larger types.

Memory Layout and Alignment

The way bit-fields are packed into memory is highly implementation-defined and depends on the target architecture’s Application Binary Interface (ABI).
  • Storage Units: Compilers allocate addressable storage units (typically the size of the declared type, e.g., 4 bytes for int). Bit-fields are packed into these units.
  • Ordering: Whether bit-fields are allocated right-to-left (least significant bit to most significant bit) or left-to-right is implementation-defined.
  • Boundary Crossing: If a bit-field does not fit into the remaining space of the current storage unit, whether it is split across two units or placed entirely in the next unit is implementation-defined.

Thread Safety and the C11 Memory Model

Under the C11 memory model, adjacent bit-fields share the same memory location. Modifying different adjacent bit-fields concurrently from multiple threads results in a data race, even if the threads are writing to distinct logical members. To safely modify bit-fields concurrently, they must belong to different memory locations. This requires separating the bit-fields with a zero-width bit-field or a non-bit-field member.

Special Constructs

Unnamed Bit-fields

A bit-field can be declared without a name. This is used exclusively for padding to conform to specific memory layouts. Unnamed bit-fields cannot be accessed or initialized.
struct PaddingExample {
    unsigned int field1 : 4;
    unsigned int        : 4;  // 4 bits of inaccessible padding
    unsigned int field2 : 8;
};

Zero-Width Bit-fields

An unnamed bit-field with a width of 0 forces the compiler to align the next bit-field to the boundary of the next addressable storage unit. Under C11, this also establishes a boundary between memory locations, preventing data races between the bit-fields on either side.
struct AlignmentExample {
    unsigned int field1 : 4;
    unsigned int        : 0;  // Forces alignment; separates memory locations
    unsigned int field2 : 4;  // Starts in a new storage unit
};

Language Restrictions

Because bit-fields do not necessarily begin or end on byte boundaries, the C language imposes strict limitations on their usage:
  1. No Pointers: The address-of operator (&) cannot be applied to a bit-field. You cannot create a pointer to a bit-field.
  2. No sizeof: The sizeof operator cannot be applied to a bit-field, as sizeof evaluates to a number of bytes, and a bit-field may occupy a fractional byte.
  3. No alignof: The _Alignof (or alignof) operator cannot be applied to a bit-field.
  4. No Arrays: You cannot declare an array of bit-fields.
  5. Width Limits: The specified width cannot exceed the bit width of the underlying type (e.g., unsigned int x : 33; is invalid on a system where unsigned int is 32 bits).
Master C with Deep Grasping Methodology!Learn More