Easy Tutorial
❮ C Exercise Example85 C Exercise Example45 ❯

Bit Fields

If the structure of a program contains multiple switch variables, each being a TRUE/FALSE variable, like this:

struct
{
  unsigned int widthValidated;
  unsigned int heightValidated;
} status;

This structure requires 8 bytes of memory space, but in reality, we only store 0 or 1 in each variable. In such cases, C provides a better way to utilize memory space. By defining the width of variables within the structure, you can instruct the compiler to use only these bytes. For example, the above structure can be rewritten as:

struct
{
  unsigned int widthValidated : 1;
  unsigned int heightValidated : 1;
} status;

Now, the status variable in the above structure will occupy 4 bytes of memory space, but only 2 bits are used to store values. If you use 32 variables, each with a width of 1 bit, the status structure will use 4 bytes. However, if you add one more variable, making it 33 variables, it will allocate the next segment of memory to store the 33rd variable, thus using 8 bytes. Let's look at the following example to understand this concept:

Example

#include <stdio.h>
#include <string.h>

/* Define simple structure */
struct
{
  unsigned int widthValidated;
  unsigned int heightValidated;
} status1;

/* Define bit field structure */
struct
{
  unsigned int widthValidated : 1;
  unsigned int heightValidated : 1;
} status2;

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

   return 0;
}

When the above code is compiled and executed, it produces the following result:

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

Bit Field Declaration

Some information does not need to occupy a full byte and only requires a few or one bit. For example, storing a switch variable with only 0 and 1 states can be done with 1 bit. To save storage space and simplify processing, C provides a data structure called "bit field" or "bit segment".

A "bit field" divides a byte into different areas and specifies the number of bits for each area. Each field has a name, allowing operations by field name. This way, several different objects can be represented using a byte's bit fields.

Typical examples:

Bit Field Definition and Bit Field Variable Declaration

Bit field definition is similar to structure definition, in the form:

struct bit_field_structure_name 
{
  bit_field_list
};

Where the bit field list is in the form:

type [member_name] : width ;

Here is a description of the bit field elements:

Element Description
type Can only be int, unsigned int, or signed int, determining how the bit field value is interpreted.
member_name The name of the bit field.
width The number of bits in the bit field. The width must be less than or equal to the bit width of the specified type.

Variables with predefined widths are called bit fields. A bit field can store more than 1 bit. For example, to store values from 0 to 7, you can define a bit field with a width of 3 bits, like this:

struct
{
  unsigned int age : 3;
} Age;

The above structure instructs the C compiler that the age variable will only use 3 bits to store the value. If you try to use more than 3 bits, it will not be possible.

struct bs{
    int a:8;
    int b:2;
    int c:6;
}data;

data is a bs variable, occupying two bytes in total. The bit field a occupies 8 bits, bit field b occupies 2 bits, and bit field c occupies 6 bits.

Let's look at another example:

struct packed_struct {
  unsigned int f1:1;
  unsigned int f2:1;
  unsigned int f3:1;
  unsigned int f4:1;
  unsigned int type:4;
  unsigned int my_int:9;
} pack;

Here, packed_struct contains 6 members: four 1-bit identifiers f1..f4, a 4-bit type, and a 9-bit my_int.

Let's look at the following example:

Example

#include <stdio.h>
#include <string.h>

struct
{
  unsigned int age : 3;
} Age;

int main( )
{
   Age.age = 4;
   printf( "Sizeof( Age ) : %d\n", sizeof(Age) );
   printf( "Age.age : %d\n", Age.age );

   Age.age = 7;
   printf( "Age.age : %d\n", Age.age );

   Age.age = 8; // Binary representation is 1000, which has four bits, exceeding the limit
   printf( "Age.age : %d\n", Age.age );

   return 0;
}

When the above code is compiled, it comes with a warning. When executed, it produces the following result:

Sizeof( Age ) : 4
Age.age : 4
Age.age : 7
Age.age : 0

Notes on Bit Field Definition:

In this bit field definition, a occupies the first byte's 4 bits, the next 4 bits are filled with 0 and not used, b starts from the second byte, occupying 4 bits, and c occupies 4 bits.

From the above analysis, it can be seen that a bit field is essentially a structure type, but its members are allocated in bits.

Bit Field Usage

Bit fields are used similarly to structure members, with the general form:

bit_field_variable_name.bit_field_name
bit_field_variable_name->bit_field_name

Bit fields can be output in various formats.

Please look at the following example:

Example

#include <stdio.h>

int main(){
    struct bs{
        unsigned a:1;
        unsigned b:3;
        unsigned c:4;
    } bit,*pbit;
    bit.a=1;    /* Assign value to bit field (should not exceed the allowed range) */
    bit.b=7;    /* Assign value to bit field (should not exceed the allowed range) */
    bit.c=15;    /* Assign value to bit field (should not exceed the allowed range) */
    printf("%d,%d,%d\n",bit.a,bit.b,bit.c);    /* Output the contents of the three fields in integer format */
    pbit=&bit;    /* Assign the address of bit field variable bit to pointer variable pbit */
    pbit->a=0;    /* Reassign value to bit field a using pointer, set to 0 */
    pbit->b&=3;    /* Use compound bitwise operator "&=", equivalent to: pbit->b=pbit->b&3, the original value of bit field b is 7, the result of bitwise AND with 3 is 3 (111&011=011, decimal value is 3) */
    pbit->c|=1;    /* Use compound bitwise operator "|=", equivalent to: pbit->c=pbit->c|1, the result is 15 */
    printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c);    /* Output the values of these three fields using pointer */
}

The above program defines a bit field structure bs with three bit fields a, b, and c. It declares a bs type variable bit and a pointer variable pbit pointing to bs type. This indicates that bit fields can also use pointers.

❮ C Exercise Example85 C Exercise Example45 ❯