Bit fields in structures. Examples
Contents
- 1. Bit fields. General concepts
- 2. An example of using bit fields in a Date structure describing the date of the day and the number of the day in the week
- 3. An example of comparing a structure with bit fields to a structure that does not use bit fields. The Time structure
- Related topics
Search other resources:
1. Bit fields. General concepts
Structures allow you to conveniently group data (variables) according to some criteria. In memory, such data, as a rule, are placed one after another according to the declaration. In the C++ language there is a means of compressing the size of the memory allocated for the variables declared in the structure. These are bit fields in structures.
Bit fields are used to store data of integer types. When using bit fields in the size of the type, a strictly defined number of bits are allocated for them.
There are times when the size of the memory that is allocated for storing data is too large. For example, to store data about the day of the week, the size of 1 byte or 8 bits is too much. There are 7 days of the week, so 3 bits are enough to represent this data (2 to the power of 3 = 8 values).
The bitfield declaration in the structure looks like this
unsigned int field : value;
here
- field – the name of the field (variable) in the structure;
- value – the number of bits allocated to represent the set of bit field values.
In turn, the declaration of a structure containing bit fields looks like this:
struct StructName { unsigned int field_1 : value_1; unsigned int field_2 : value_2; ... unsigned int field_N : value_N };
here
- StructName – the name of the structure;
- field_1, field_2, field_N – variable names that correspond to the bit fields of the structure;
- value_1, value_2, value_N – integer values representing the number of allocated bits for the sizes of fields field_1, field_2, field_N respectively.
It is recommended to use unsigned int type as bit fields. This will not distort the result if the first bit is set to 1, which will mean a negative number. However, when using other integer types, the compiler will not generate errors.
Declaring only one bitfield in the structure has no effect. Data in memory will still be stored in multiples of 8 bits or 1 byte (alignment). The usefulness of bit fields increases when a large amount of integer data is stored in the structure. With a large number of bit fields, you can save a significant amount of bytes for the same data set without losing them. In turn, the use of arrays of structures with bit fields can significantly reduce the size of stored data and speed up the execution of commands for processing this data.
⇑
2. An example of using bit fields in a Date structure describing the date of the day and the number of the day in the week
The task declares the Day structure that describes the following data about the day:
- the number of the day in the week from 1 to 7. Here 1 is Monday, 2 is Tuesday, etc., 7 is Sunday;
- day number in the month – 1..31;
- month number – 1..12;
- year. The range is from 0 to 3000.
To represent the day of the week, 3 bits are sufficient, since 3 bits yield 8 values (2^3=8). That is, 8 values cover 7 values that are required to store the weekday number. Based on the above reasoning about the day of the week, you can form the number of bits for other fields of the Day structure:
- the number in the month is enough to represent 5 bits (2^5 = 32, 32>31);
- it is enough to represent the month number with 4 bits (2^4 = 16, 16>12);
- 12 bits are enough to store the year (2^12 = 4096, 4096>3000).
The demo program text is as follows
#include <iostream> using namespace std; struct Day { unsigned int weekDay : 3; // day of week 1..7 unsigned int number : 5; // day number in month 1..31 unsigned int month : 4; // month number 1..12 unsigned int year : 12; // year 0..3000 }; void main() { // Bit fields in structures // 1. Declare structure Day d; // 2. Fill the structure with data 01/14/2022, Friday d.weekDay = 5; d.number = 14; d.month = 1; d.year = 2022; // 3. Print data cout << "d.weekDay = " << d.weekDay << endl; cout << "d.number = " << d.number << endl; cout << "d.month = " << d.month << endl; cout << "d.year = " << d.year << endl; // 4. Display the size of structure cout << "sizeof(Day) = " << sizeof(d) << endl; // 4 bytes }
Program result
d.weekDay = 5 d.number = 14 d.month = 1 d.year = 2022 sizeof(Day) = 4
⇑
3. An example of comparing a structure with bit fields to a structure that does not use bit fields. The Time structure
Let it be necessary to implement the Time structure, which describes the time interval in the form
hours : minutes : seconds : milliseconds
here
- hours – number of hours in one day 0..23;
- minutes – number of minutes per hour 0..59;
- seconds – the number of seconds per minute 0..59;
- milliseconds – number of milliseconds 0..999.
Bitfields are best used to describe such data in a structure. Based on the maximum allowable values, for different time intervals it is possible to allocate a different number of bits in their representation in structures:
- the hours field – 5 bits (2^5 = 32>23). From 5 bits, you can form up to 2^5 = 32 different values, which is enough to represent 24 values of this field;
- minutes – 6 bits (2^6 = 64 > 59);
- seconds – 6 bits (2^6 = 64 > 59);
- milliseconds – 10 bits (2^10 = 1024 > 999).
In the program, for the purpose of demonstration, two structures Time and Time2 are created, in which the necessary fields for representing time are implemented. However, the Time structure uses bitfields, and the Time2 structure uses ordinary unsigned int values.
The program text is as follows
#include <iostream> using namespace std; // The Time structure uses bit fields struct Time { unsigned int hours : 5; unsigned int minutes : 6; unsigned int seconds : 6; unsigned int milliseconds : 10; }; // Time2 structure does not use fields struct Time2 { unsigned int hours; unsigned int minutes; unsigned int seconds; unsigned int milliseconds; }; void main() { // Comparison of structures with and without bit fields // 1. Declare the variables Time tm; Time2 tm2; // 2. Using structures in the program // 2.1. The structure of Time type tm.hours = 12; tm.seconds = 36; tm.milliseconds = 777; tm.minutes = 3; // 2.2. The structure of Time2 type tm2.hours = 20; tm2.seconds = 39; tm2.milliseconds = 555; tm2.minutes = 55; // 3. Determine and display the size of the Time, Time2 structures // using the sizeof() operator size_t sizeTime = sizeof(Time); // 4 size_t sizeTime2 = sizeof(Time2); // 16 cout << "sizeTime = " << sizeTime << endl; cout << "sizeTime2 = " << sizeTime2 << endl; }
Program result
sizeTime = 4 sizeTime2 = 16
As you can see from the result, there is no difference between the use of ordinary structures and bit structures (access to fields, filling with data, etc.). However, the size of the bit structure (variable tm) in memory is only 4 bytes compared to the size of the ordinary structure of 16 bytes.
In the Time structure, bits are added to the fields. The total number of bits is
5 + 6 + 6 + 10 = 27
If you divide 27 by 8 (the number of bits in a byte), you get 3 with an excess. That is, to represent 27 bits, 4 bytes are needed to correctly display the data.
⇑
Related topics
- Composite data types. The template of structure. Structural variable. Structures in the CLR. Declaring and initializing a structured variable
- Unions. The keyword ‘union’. Examples of declaring and using unions
⇑