Bit Fields in Structures
Pack data efficiently with bit fields! Learn to define structure members that use specific numbers of bits, saving memory in embedded systems and protocols.
Track Your Progress
Sign in to save your learning progress
What You Will Learn
- ✓Define bit fields in structures
- ✓Understand bit field memory layout
- ✓Use bit fields for flags and options
- ✓Know bit field limitations and portability issues
- ✓Apply bit fields in real-world scenarios
01What are Bit Fields?
Bit fields allow you to define structure members that occupy a specific number of bits. This is useful for packing multiple small values into a single word of memory.
Why Use Bit Fields?
Memory Efficiency
Store multiple flags in a single byte instead of using separate integers
Hardware Mapping
Match hardware register layouts in embedded systems
Protocol Headers
Define network packet structures with specific bit widths
Clean Code
Access individual bits using struct member syntax instead of bitwise operations
02Bit Field Syntax
1struct {2 type member_name : width;3};45// Example: Status flags6struct Status {7 unsigned int is_active : 1; // 1 bit (0 or 1)8 unsigned int priority : 3; // 3 bits (0-7)9 unsigned int mode : 4; // 4 bits (0-15)10}; // Total: 8 bits = 1 byteMemory Layout Visualization
03Practical Examples
Example 1: File Permissions
1#include <stdio.h>23struct FilePermissions {4 unsigned int read : 1;5 unsigned int write : 1;6 unsigned int execute : 1;7 unsigned int hidden : 1;8 unsigned int system : 1;9 unsigned int archive : 1;10};1112int main() {13 struct FilePermissions perm;14 15 // Set permissions16 perm.read = 1;17 perm.write = 1;18 perm.execute = 0;19 perm.hidden = 0;20 perm.system = 0;21 perm.archive = 1;22 23 printf("File permissions:\n");24 printf("Read: %d\n", perm.read);25 printf("Write: %d\n", perm.write);26 printf("Execute: %d\n", perm.execute);27 printf("Size of struct: %zu bytes\n", sizeof(perm));28 29 return 0;30}Expected Output:
Read: 1
Write: 1
Execute: 0
Size of struct: 4 bytes
Example 2: Date Structure
1#include <stdio.h>23// Pack a date into just 2 bytes (16 bits)4struct PackedDate {5 unsigned int day : 5; // 1-31 (needs 5 bits)6 unsigned int month : 4; // 1-12 (needs 4 bits)7 unsigned int year : 7; // 0-127 (offset from 2000)8};910int main() {11 struct PackedDate today;12 today.day = 27;13 today.month = 1;14 today.year = 26; // 202615 16 printf("Date: %02d/%02d/%d\n", 17 today.day, today.month, 2000 + today.year);18 printf("Size: %zu bytes\n", sizeof(today));19 20 // Compare to unpacked version21 struct UnpackedDate {22 int day;23 int month;24 int year;25 };26 printf("Unpacked size: %zu bytes\n", sizeof(struct UnpackedDate));27 28 return 0;29}Expected Output:
Size: 2 bytes
Unpacked size: 12 bytes
Example 3: Hardware Register (Embedded)
1// Typical GPIO configuration register2struct GPIO_Config {3 unsigned int pin_mode : 2; // 00=input, 01=output, 10=alternate, 11=analog4 unsigned int output_type : 1; // 0=push-pull, 1=open-drain5 unsigned int output_speed : 2; // 00=low, 01=medium, 10=high, 11=very high6 unsigned int pull_up_down : 2; // 00=none, 01=pull-up, 10=pull-down7 unsigned int reserved : 1; // Unused bit8};910// Usage in embedded systems11void configure_gpio_as_output(volatile struct GPIO_Config* gpio) {12 gpio->pin_mode = 0b01; // Output13 gpio->output_type = 0; // Push-pull14 gpio->output_speed = 0b11; // Very high speed15 gpio->pull_up_down = 0b00; // No pull-up/down16}04Important Rules and Limitations
1. Cannot take address of bit fields
1struct S { unsigned int flag : 1; };2struct S s;3// int* p = &s.flag; // ERROR! Cannot take address2. Allowed types are implementation-defined
C standard requires int, unsigned int, and _Bool. Other types like charmay or may not work depending on compiler.
3. Bit order is implementation-defined
Whether bits are allocated from LSB to MSB or vice versa depends on the compiler and architecture. Don't assume a specific layout for portability.
4. Unnamed bit fields create padding
1struct Example {2 unsigned int a : 5;3 unsigned int : 3; // 3 bits of padding (unnamed)4 unsigned int b : 8;5 unsigned int : 0; // Force alignment to next unit boundary6 unsigned int c : 4;7};Portability Warning
Bit field layout is not portable across different compilers or architectures. If you need exact binary layouts (like network protocols), use explicit bitwise operations instead.
05Bit Fields vs Bitmasks
Bit Fields
1struct Flags {2 unsigned int a : 1;3 unsigned int b : 1;4 unsigned int c : 1;5};67struct Flags f;8f.a = 1;9f.b = 0;10if (f.c) { ... }Cleaner syntax, but not portable
Bitmasks
1#define FLAG_A (1 << 0)2#define FLAG_B (1 << 1)3#define FLAG_C (1 << 2)45unsigned int flags = 0;6flags |= FLAG_A; // Set7flags &= ~FLAG_B; // Clear8if (flags & FLAG_C) { ... }More verbose, but fully portable
06Summary
- * Bit fields pack multiple values into fewer bytes
- * Syntax:
unsigned int name : bits; - * Cannot take the address of a bit field
- * Layout is not portable - use bitmasks for protocols
- * Great for memory-constrained embedded systems
Test Your Knowledge
Related Tutorials
Bitmasks and Bit Manipulation
Work with individual bits! Set, clear, toggle, and check bits. Implement permission systems and flags efficiently.
const and volatile Keywords
Master the const and volatile type qualifiers. Learn to create read-only variables, pointers to const, const pointers, and understand volatile for hardware programming.
Structures in C
Group related data together! Create your own data types with struct. Store a student's name, age, and grade in one variable.
Have Feedback?
Found something missing or have ideas to improve this tutorial? Let us know on GitHub!