The following two examples demonstrate the use of bit fields
to reduce memory consumption of certain applications.
In the first example we create a compressed ‘bit’ struct and on the second we create a weird struct representation for bytes to show that the size of that struct is significantly less that the original one.
First example: Using bit fields to create a ‘bit’ structure
[download id=”2693″]
#include <stdio.h> // Weird structure to represent a 'bit' typedef struct { unsigned char value; } bit; // 'bit' structure using bit fields typedef struct { unsigned char value : 1; } bit_bit_field; int main( ) { printf( "Memory size occupied by 'bit' struct : %zu bytes\n", sizeof(bit)); printf( "Memory size occupied by 'bit_bit_field' struct : %zu bytes\n", sizeof(bit_bit_field)); bit bits[8]; bit_bit_field bits_bit_field[8]; printf( "Memory size occupied by 'bits' array : %zu bytes\n", sizeof(bits)); printf( "Memory size occupied by 'bits_bit_field' array : %zu bytes\n", sizeof(bits_bit_field)); // Setting the value of the first 'bit' and then printing it. // We will use various values for this test to show that when you set a value to a bit field // that is greater that the allowed size it will fill it using the last bits only. // It will not spill data though to neighbouring 'bits'. unsigned char value; for (value = 0; value < 4; value++) { printf("Input Value: %d\n", value); int bits_i; const int bits_length = (sizeof(bits) / sizeof(bit)); for (bits_i = 0; bits_i < bits_length; bits_i++) { if (bits_i % 2) { bits[bits_i].value = 0; } else { bits[bits_i].value = value; } printf("%d", bits[bits_i].value); } printf("\n"); int bits_bit_field_i; const int bits_bit_field_length = (sizeof(bits_bit_field) / sizeof(bit_bit_field)); for (bits_bit_field_i = 0; bits_bit_field_i < bits_bit_field_length; bits_bit_field_i++) { if (bits_bit_field_i % 2) { bits_bit_field[bits_bit_field_i].value = 0; } else { bits_bit_field[bits_bit_field_i].value = value; } printf("%d", bits_bit_field[bits_bit_field_i].value); } printf("\n"); } return 0; }
[download id=”2693″]
Execution output
Memory size occupied by 'bit' struct : 1 bytes Memory size occupied by 'bit_bit_field' struct : 1 bytes Memory size occupied by 'bits' array : 8 bytes Memory size occupied by 'bits_bit_field' array : 8 bytes Input Value: 0 00000000 00000000 Input Value: 1 10101010 10101010 Input Value: 2 20202020 00000000 Input Value: 3 30303030 10101010
Second example: Using bit fields to create a ‘byte’ structure where each ‘bit’ is another named member
[download id=”2692″]
#include <stdio.h> // Weird structure to represent a 'byte' typedef struct { unsigned char bit_0; unsigned char bit_1; unsigned char bit_2; unsigned char bit_3; unsigned char bit_4; unsigned char bit_5; unsigned char bit_6; unsigned char bit_7; } byte; // 'byte' structure using bit fields // Unfortunately we cannot declare an array where the values are bit fields, // so we have to declare each member separately. // We instruct the compiler to use only one bit per element. typedef struct { unsigned char bit_0 : 1; unsigned char bit_1 : 1; unsigned char bit_2 : 1; unsigned char bit_3 : 1; unsigned char bit_4 : 1; unsigned char bit_5 : 1; unsigned char bit_6 : 1; unsigned char bit_7 : 1; } byte_bit_field; int main( ) { printf( "Memory size occupied by 'byte' struct : %zu bytes\n", sizeof(byte)); printf( "Memory size occupied by 'byte_bit_field' struct : %zu bytes\n", sizeof(byte_bit_field)); byte bytes[8]; byte_bit_field bytes_bit_field[8]; printf( "Memory size occupied by 'bytes' array : %zu bytes\n", sizeof(bytes)); printf( "Memory size occupied by 'bytes_bit_field' array : %zu bytes\n", sizeof(bytes_bit_field)); // Setting the value of the first 'bit' and then printing it. // We will use various values for this test to show that when you set a value to a bit field // that is greater that the allowed size it will fill it using the last bits only. // It will not spill data though to neighbouring 'bits'. unsigned char value; for (value = 0; value < 4; value++) { printf("Input Value: %d\n", value); int bytes_i; const int bytes_length = (sizeof(bytes) / sizeof(byte)); for (bytes_i = 0; bytes_i < bytes_length; bytes_i++) { if (bytes_i % 2) { bytes[bytes_i].bit_3 = 0; } else { bytes[bytes_i].bit_3 = value; } printf(" %d ", bytes[bytes_i].bit_3); } printf("\n"); int bytes_bit_field_i; const int bytes_bit_field_length = (sizeof(bytes_bit_field) / sizeof(byte_bit_field)); for (bytes_bit_field_i = 0; bytes_bit_field_i < bytes_bit_field_length; bytes_bit_field_i++) { if (bytes_bit_field_i % 2) { bytes_bit_field[bytes_bit_field_i].bit_3 = 0; } else { bytes_bit_field[bytes_bit_field_i].bit_3 = value; } printf("%d%d%d ", bytes_bit_field[bytes_bit_field_i].bit_2, bytes_bit_field[bytes_bit_field_i].bit_3, bytes_bit_field[bytes_bit_field_i].bit_4); } printf("\n"); } return 0; }
[download id=”2692″]
Execution output
Memory size occupied by 'byte' struct : 8 bytes Memory size occupied by 'byte_bit_field' struct : 1 bytes Memory size occupied by 'bytes' array : 64 bytes Memory size occupied by 'bytes_bit_field' array : 8 bytes Input Value: 0 0 0 0 0 0 0 0 0 000 000 000 000 000 000 000 000 Input Value: 1 1 0 1 0 1 0 1 0 010 000 010 000 010 000 010 000 Input Value: 2 2 0 2 0 2 0 2 0 000 000 000 000 000 000 000 000 Input Value: 3 3 0 3 0 3 0 3 0 010 000 010 000 010 000 010 000
This post is also available in: Greek