Bit Field in C

Abdul Mateen Oct 12, 2023
  1. Bit Field in C
  2. Bit Field Storage in C
  3. Bit Field With the short Data Type in C
  4. Bit Field With Multiple Data Types in C
  5. Conclusion
Bit Field in C

In this tutorial, we will learn about the bit field in the C language.

We will start the discussion from the bit field. Next, we will discuss bit field storage, followed by the syntax of the bit field in C language.

Lastly, we will see a bit field with different data types to understand the minimum and maximum space consumed by the structure having a bit field inside.

Bit Field in C

A bit field in programming is a unique data structure that helps the programmer to save memory. The bit field allows the allocation of memory to structures in bits.

Let’s consider a pure black & white image having only two colors black & white. We need to store only two values: 0 or 1.

Consider a small 100x100 image comparing the screen with thousands of pixels in each dimension. There will be ten thousand pixels in the image.

In standard data types, you have an option of unsigned char data type in C language, which takes only one byte; however, to save a pure black and white image, you need 10000 bytes of memory.

Using the bit field, you can save eight pixels in one byte (8 bits in 1 byte). This means you will need around 1250 bytes instead of 10000.

This is just an example; this doesn’t mean you can save space in the case of images only. In some examinations, where thousands of candidates appear, you only need one bit to store pass/fail information; otherwise, the option is to use one byte for each candidate.

Bit Field Storage in C

Consider the following structure to start a discussion on bit field storage:

struct {
  unsigned char is_married;
  unsigned char is_graduated;
} status0;

This structure requires two bytes of memory space; however, we have to store either 0 or 1 in both fields. Let’s move ahead to a better way to save space.

We will see the bit field from syntax to code in detail.

In C language, we have a specific syntax to tell the number of bits required with each variable:

struct {
  type[variable_name] : size;  // Size will be in bits
}

This is important to note that this syntax is available with structure. Here, type is any data type like int, char, short, unsigned char, etc.

You are already well aware of legal variable names in C language. The colon is part of the syntax and is required between variable name and size, and lastly, size is the number of bits required.

The next thing that might surprise you is the size of the structure with bit size. See the following code:

#include <stdio.h>

struct {
  unsigned char is_married;
  unsigned char is_graduated;
} status0;

struct {
  unsigned char is_married : 1;
  unsigned char is_graduated : 1;
} status1;

int main() {
  printf("Memory size occupied by status1 : %ld bytes\n", sizeof(status0));
  printf("Memory size occupied by status1 : %ld  bytes\n", sizeof(status1));
  return 0;
}

The output is:

Memory size occupied by status1 : 2 bytes
Memory size occupied by status1 : 1 bytes

In the output, the first structure takes 2 bytes (i.e., 1 byte for each field), which is very logical. However, the second output takes 1 byte; you might expect 2 bytes or bits.

The question is, why one byte? The logic is that the data type will consume one byte per the C language’s routine definition.

However, specifying the size in bits allows the programmer to declare 7 more fields of 1 bit each.

The total bits should remain less than equal to 8 bits for 1 byte. Otherwise, 2 bytes of storage will be consumed.

See the following codes:

#include <stdio.h>

struct {
  unsigned char a : 1;
  unsigned char b : 7;
} status0;

struct {
  unsigned char a : 1;
  unsigned char b : 1;
  unsigned char c : 1;
  unsigned char d : 1;
  unsigned char e : 1;
  unsigned char f : 1;
  unsigned char g : 1;
  unsigned char h : 1;
} status1;

int main() {
  printf("Memory size occupied by status1 : %ld\n", sizeof(status0));
  printf("Memory size occupied by status1 : %ld\n", sizeof(status1));
  return 0;
}

The output is:

Memory size occupied by status1 : 1
Memory size occupied by status1 : 1

Let’s look at the next example, where the number of bits is increased:

#include <stdio.h>

struct {
  unsigned char a : 3;
  unsigned char b : 7;
  unsigned char c : 7;
} status0;

struct {
  unsigned char a : 1;
  unsigned char b : 1;
  unsigned char c : 1;
  unsigned char d : 1;
  unsigned char e : 1;
  unsigned char f : 1;
  unsigned char g : 1;
  unsigned char h : 1;
  unsigned char i : 1;
  unsigned char j : 1;
} status1;

int main() {
  printf("Memory size occupied by status1 : %ld\n", sizeof(status0));
  printf("Memory size occupied by status1 : %ld\n", sizeof(status1));
  return 0;
}

The output is:

Memory size occupied by status1 : 3
Memory size occupied by status1 : 2

In the first structure, the total bits are 3+7+7=17, which is greater than 16 bits (2 bytes). Therefore, 3 bytes will be consumed.

The same is visible in the first line of output.

In the 2nd structure, we have 10 fields of 1 bit each, which requires 10 bits; therefore, it will consume two bytes. Again, the 2nd line of output confirms the concept.

Bit Field With the short Data Type in C

One might get that an unsigned char is required to use the bit field. We can use the bit field with other data types as well.

Here, we are considering the short data type to demonstrate and to get more grip on the concept of the bit field.

Consider the following code:

#include <stdio.h>

struct {
  unsigned short a : 3;
} status0;

struct {
  unsigned short a : 3;
  unsigned short b : 9;
  unsigned short c : 4;
} status1;

int main() {
  printf("Memory size occupied by status1 : %ld\n", sizeof(status0));
  printf("Memory size occupied by status1 : %ld\n", sizeof(status1));
  return 0;
}

The output is:

Memory size occupied by status1 : 2
Memory size occupied by status1 : 2

In both structures, the memory consumed is 2 bytes because short takes 2 bytes. Therefore, the minimum required memory is 2 bytes.

However, multiple fields may consume a total of 16 bits ( as depicted in the second structure) the size will remain at 2 bytes.

If the number of bits increases from 16, the next two bytes of the short data type are covered automatically, and as a result, four 4 will be consumed.

Let’s look at the following C program:

#include <stdio.h>

struct {
  unsigned short a : 6;
  unsigned short b : 6;
  unsigned short c : 7;
} status1;

int main() {
  printf("Memory size occupied by status1 : %ld\n", sizeof(status1));
  return 0;
}

Here, the total bits are 6+6+7=19, so the output is:

Memory size occupied by status1 : 4

Notice that the memory increases byte by byte because char has one-byte storage; whereas, in the case of short, memory is increasing by two bytes because the short, by definition, has two bytes storage.

Bit Field With Multiple Data Types in C

Now, it’s the right time to discuss bit field storage requirements in case the structure has two or more data types. In such a case, the minimum required bytes are the maximum space required by the largest datatype in the structure.

For example, if a structure has members of short and char, the largest type is short and requires 2 bytes; the whole structure will require a minimum of two bytes.

In the case of int & short, the int is the largest type; hence, the whole structure requires 4 bytes. Let’s demonstrate the concept with the help of the following code example:

#include <stdio.h>

struct {
  unsigned short a : 6;
  unsigned int b : 6;
} status1;

struct {
  unsigned long long a : 6;
  unsigned int b : 6;
  unsigned short c : 6;
} status2;

int main() {
  printf("Memory size occupied by status1 : %ld\n", sizeof(status1));
  printf("Memory size occupied by status1 : %ld\n", sizeof(status2));
  return 0;
}

The output is:

Memory size occupied by status1 : 4 Memory size occupied by status1 : 8

In the first structure, the int is the largest data type; therefore, the first line of output shows 4 bytes structure size.

In the second structure, the long long is the dominating type, so the second line of output shows eight bytes size of the structure.

Lastly, the increment in case of multiple data sizes will be simple; the increment step is the size is equal to the number of bytes in the largest type of structure.

Let’s look into the following code to get a better understanding:

#include <stdio.h>

struct {
  unsigned short a : 6;
  unsigned int b : 30;
  unsigned long long c : 50;
} status1;

int main() {
  printf("Memory size occupied by status1 : %ld\n", sizeof(status1));
  return 0;
}

The structure has 50+30+6=86 bits, whereas 8 bytes have 64 bits. Therefore, this structure required double space, as depicted in the output below:

Memory size occupied by status1 : 16

We need 16 bytes which id 8+8 bytes.

Conclusion

We can save space if we are using multiple-bit fields in our program. We can specify the number of bits for a structure member variable at the time of declaration.

The minimum size of the structure is the maximum bytes required for the largest datatype in the structure.

If the single or multiple fields collectively consume more bits than the size of the largest type in the structure, the memory consumed will be in the multiple of the size of the maximum memory type.

Related Article - C Struct