In memory-constrained embedded microcontrollers and network protocol headers, saving every single byte of RAM is critical. Standard C data types use a minimum of 8 bits (char) or 32 bits (int), even if a variable only needs to store a boolean flag (1 bit) or a status code from 0 to 7 (3 bits). C bitfields allow you to pack multiple variables into specific bit widths within a single integer boundary.

RAM Memory Packing: Standard Struct vs Bitfield Struct

Memory Consumption Comparison: 16 Bytes vs 4 Bytestext
+---------------------------------------------------------------------------------+
| STANDARD STRUCT (Consumes 16 Bytes due to Alignment & Padding)                  |
+---------------------------------------------------------------------------------+
| int is_enable (4B) | int is_error (4B) | int mode (4B) | int speed (4B)            |
+---------------------------------------------------------------------------------+
 
+---------------------------------------------------------------------------------+
| BITFIELD STRUCT (Consumes ONLY 4 Bytes - 32-bit Container)                      |
+---------------------------------------------------------------------------------+
| Bit 0: is_enable (1b) | Bit 1: is_error (1b) | Bits 2-4: mode (3b)              |
| Bits 5-8: speed (4b)  | Bits 9-31: Unused / Reserved (23b)                      |
+---------------------------------------------------------------------------------+

Production Implementation: Microcontroller Control Register

hardware_bitfields.cc
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
 
// Define packed 32-bit peripheral register using bitfields
typedef struct {
    uint32_t enable     : 1;  // Bit 0: Enable device (0 = Off, 1 = On)
    uint32_t ready      : 1;  // Bit 1: Ready status flag
    uint32_t mode       : 3;  // Bits 2-4: Operating Mode (0-7)
    uint32_t tx_power   : 4;  // Bits 5-8: TX Power level (0-15)
    uint32_t reserved   : 23; // Bits 9-31: Reserved for hardware alignment
} SystemControlReg;
 
int main(void) {
    SystemControlReg ctrl = {0};
 
    // Assigning values directly to bitfield members
    ctrl.enable = 1;
    ctrl.ready = 1;
    ctrl.mode = 5;       // Binary 101
    ctrl.tx_power = 12;  // Binary 1100
 
    printf("Struct Memory Size: %zu bytes\n", sizeof(SystemControlReg));
    printf("Enable: %u | Ready: %u | Mode: %u | Power: %u\n",
           ctrl.enable, ctrl.ready, ctrl.mode, ctrl.tx_power);
 
    return 0;
}

Key Insights from Bitfield Syntax:

  • Bit-Width Specifier (`: N`): Specifies the exact number of binary bits allocated to that member.

  • Unsigned Base Types: Always use unsigned int or uint32_t for bitfields to prevent sign extension bugs.