Bit fields allow structure and class members to use a specified number of bits for storing values. They are mainly used to reduce memory usage when only a few bits are required.
- Specifies the number of bits allocated to a structure or class member.
- Used for memory optimization when storing small integer values.
Example: if a member stores values from 0 to 15, only 4 bits are required. A bit field allows allocating just those 4 bits instead of using the full storage of an integer member.
Syntax
A bit field is declared by specifying the data type followed by the member name and the required bit width.
Bit Field in a Structure
struct StructName {
dataType fieldName : width;
};
Bit Field in a Class
class ClassName {
public:
dataType fieldName : width;};
where:
- dataType is an integral type.
- width specifies the number of bits allocated to the member.
Note: Bit fields can only be declared using integral data types such as int, unsigned int, char, or bool.
Bit Fields in Structures
Bit fields can be used in structures to reduce the memory occupied by members that require only a limited number of bits.
- Specifies the number of bits allocated to each member.
- Helps reduce the overall size of the structure.
Example: The following program compares the size of a structure with and without bit fields.
#include <iostream>
using namespace std;
// Define a struct without bit fields
struct Loan1 {
unsigned int principal;
unsigned int interestRate;
unsigned int period;
};
// Define a struct with bit-fields
struct Loan2 {
// principal variable can store maximum value of
// 1,048,575
unsigned int principal : 20;
// Maximum interest rate of 63
unsigned int interestRate : 6;
// Maximum period of 63 months
unsigned int period : 6;
};
int main()
{
// printing the size of both structures
cout << "Size of Structure without Bit Fields: ";
cout << sizeof(Loan1) << " Bytes" << endl;
cout << "Size of Structure with Bit Fields: ";
cout << sizeof(Loan2) << " Bytes" << endl;
return 0;
}
Output
Size of Structure without Bit Fields: 12 Bytes Size of Structure with Bit Fields: 4 Bytes
Explanation
- Loan1 contains three unsigned int members, each occupying 4 bytes, resulting in a total size of 12 bytes.
- Loan2 allocates only 20, 6, and 6 bits for its members.
- On most systems, the total width is 32 bits (4 bytes), allowing all members to fit into a single storage unit.
Bit Fields in Classes
Bit fields work the same way in classes and can be used to optimize memory usage for class members.
- Allows class members to occupy only the required number of bits.
- Useful for storing compact data in class objects.
Example: The following program demonstrates the use of bit fields in a class.
#include <iostream>
using namespace std;
// Define a class with bit-fields for loan information
class Loan {
public:
// Maximum principal of 1,048,575
unsigned int principal : 20;
// Maximum interest rate of 63
unsigned int interestRate : 6;
// Maximum period of 63 months
unsigned int period : 6;
};
int main()
{
Loan loan1;
loan1.principal = 500000;
loan1.interestRate = 15;
loan1.period = 36;
// Print the size of loan1
// (20+6+6)/8 = 4 Bytes
// 1 Byte = 8 Bits
cout << sizeof(Loan) << " Bytes" << endl;
return 0;
}
Output
4 Bytes
Explanation
- The class allocates 20 bits for principal, 6 bits for interestRate, and 6 bits for period.
- The total width is 32 bits, so the object occupies 4 bytes on most systems.
Important Properties of Bit Fields
Bit fields have some important characteristics that should be understood while using them.
Bit Width Can Exceed the Size of the Underlying Data Type
A bit field may specify more bits than the size of its declared type. The compiler allocates additional storage as required.
#include <bits/stdc++.h>
using namespace std;
// Define a structure with bit fields
struct values {
int num : 520;
};
int main()
{
values val1;
// Assigning value to num variable
val1.num = 1;
// Print the size of struct
cout << sizeof(val1) << " Bytes" << endl;
return 0;
}
Output
80 Bytes
Explanation
- The member num requests 520 bits of storage.
- The compiler allocates enough storage units to hold these bits while satisfying alignment requirements.
- Therefore, the resulting structure occupies significantly more memory than a normal int.
Bit Fields Cannot Have Their Address Taken
A pointer or non-const reference cannot refer to a bit field because bit fields may not begin at a byte boundary.
#include <iostream>
using namespace std;
struct BitField {
unsigned int num : 1;
};
int main()
{
BitField var;
var.num = 1;
// Error: Cannot take the address of a bit field
// unsigned
unsigned int* ptr = &var.num;
// Error: Cannot create a reference to a bit field
int& ref = var.num;
cout << var.num << endl;
return 0;
}
Output
./Solution.cpp: In function 'int main()':
./Solution.cpp:15:30: error: attempt to take address of bit-field structure member 'BitField::num'
unsigned int* ptr = &var.num;
^
./Solution.cpp:18:20: error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
int& ref = var.num;
^
Explanation
- Bit fields may share the same storage unit with other members.
- Since they do not always have individual memory addresses, creating pointers or references to them is not allowed.
Applications of Bit Fields
Bit fields are commonly used when only a small number of bits is required to store data.
- Memory Optimization: Reduces memory usage by allocating only the required number of bits.
- Data Compression: Stores compact data for efficient transmission and storage.
- Hardware Registers: Represents hardware control and status registers with fixed bit layouts.
- Graphics Programming: Stores color components, pixel formats, and other bit-oriented image data efficiently.