Skip to content
Related Articles
Open in App
Not now

Related Articles

Bit Fields in C

Improve Article
Save Article
Like Article
  • Difficulty Level : Medium
  • Last Updated : 25 Oct, 2022
Improve Article
Save Article
Like Article

In C, we can specify the size (in bits) of the structure and union members. The idea of bit-field is to use memory efficiently when we know that the value of a field or group of fields will never exceed a limit or is within a small range. Bit fields are used when the storage of our program is limited. Need of bit fields in C programming language:

  • Reduces memory consumption.
  • To make our program more efficient and flexible.
  • Easy to Implement.

Applications of Bit-fields:

  • If storage is limited, we can go for bit-field.
  • When devices transmit status or information encoded into multiple bits for this type of situation bit-field is most efficient.
  • Encryption routines need to access the bits within a byte in that situation bit-field is quite useful.

For example, consider the following declaration of date without the use of bit fields.

C




#include <stdio.h>
  
// A simple representation of the date
struct date {
    unsigned int d;
    unsigned int m;
    unsigned int y;
};
  
int main()
{
    printf("Size of date is %lu bytes\n", sizeof(struct date));
    struct date dt = { 31, 12, 2014 };
    printf("Date is %d/%d/%d", dt.d, dt.m, dt.y);
}


Output: 

Size of date is 12 bytes
Date is 31/12/2014

 

The above representation of ‘date’ takes 12 bytes on a compiler whereas an unsigned int takes 4 bytes. Since we know that the value of d is always from 1 to 31, and the value of m is from 1 to 12, we can optimize the space using bit fields.

Declaration of bit-fields in C 

Bit-fields are variables that are defined using a predefined width or size. Format and the declaration of the bit-fields in C are shown below:

Syntax:

struct
{
    data_type member_name: width_of_bit-field;
};
Element Description
data_type It is an integer type that determines the bit-field value which is to be interpreted. The type may be int, signed int, or unsigned int.
member_name The member name is 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.

Example:

struct date
{
// month has value between 0 and 15, 
// so 4 bits are sufficient for month variable.
    int month : 4;
};

However, if the same code is written using signed int and the value of the fields goes beyond the bits allocated to the variable and something interesting can happen. For example, consider the same code but with signed integers:

C




// C program to demonstrate use of Bit-fields 
#include <stdio.h>
  
// Space optimized representation of the date
struct date {
    // d has value between 0 and 31, so 5 bits
    // are sufficient
    int d : 5;
  
    // m has value between 0 and 15, so 4 bits
    // are sufficient
    int m : 4;
  
    int y;
};
  
int main()
{
    printf("Size of date is %lu bytes\n",
           sizeof(struct date));
    struct date dt = { 31, 12, 2014 };
    printf("Date is %d/%d/%d", dt.d, dt.m, dt.y);
    return 0;
}


Output

Size of date is 8 bytes
Date is -1/-4/2014

The output comes out to be negative. What happened behind is that the value 31 was stored in 5 bit signed integer which is equal to 11111. The MSB is a 1, so it’s a negative number and you need to calculate the 2’s complement of the binary number to get its actual value which is what is done internally. By calculating 2’s complement you will arrive at the value 00001 which is equivalent to the decimal number 1 and since it was a negative number you get a -1. A similar thing happens to 12 in which case you get a 4-bit representation as 1100 and on calculating 2’s complement you get the value of -4.

Interesting Facts About Bit Fields in C:

1. A special unnamed bit field of size 0 is used to force alignment on the next boundary. For example, consider the following program. 

C




#include <stdio.h>
  
// A structure without forced alignment
struct test1 {
    unsigned int x : 5;
    unsigned int y : 8;
};
  
// A structure with forced alignment
struct test2 {
    unsigned int x : 5;
    unsigned int : 0;
    unsigned int y : 8;
};
  
int main()
{
    printf("Size of test1 is %lu bytes\n",
           sizeof(struct test1));
    printf("Size of test2 is %lu bytes\n",
           sizeof(struct test2));
    return 0;
}


Output: 

Size of test1 is 4 bytes
Size of test2 is 8 bytes

 

 
2. We cannot have pointers to bit field members as they may not start at a byte boundary. 

C




#include <stdio.h>
struct test {
    unsigned int x : 5;
    unsigned int y : 5;
    unsigned int z;
};
int main()
{
    struct test t;
  
    // Uncommenting the following line will make
    // the program compile and run
    printf("Address of t.x is %p", &t.x);
  
    // The below line works fine as z is not a
    // bit field member
    printf("Address of t.z is %p", &t.z);
    return 0;
}


Output: 

prog.c: In function 'main':
prog.c:14:1: error: cannot take address of bit-field 'x'
 printf("Address of t.x is %p", &t.x); 
 ^

 3. It is implementation-defined to assign an out-of-range value to a bit field member. 

C




#include <stdio.h>
struct test {
    unsigned int x : 2;
    unsigned int y : 2;
    unsigned int z : 2;
};
int main()
{
    struct test t;
    t.x = 5;
    printf("%d", t.x);
    return 0;
}


Output: 

Implementation-Dependent

4. In C++, we can have static members in a structure/class, but bit fields cannot be static. 

C++




// The below C++ program compiles and runs fine
struct test1 {
    static unsigned int x;
};
int main() {}


But this one will give error:

C++




// But below C++ program fails in the compilation
// as bit fields cannot be static
struct test1 {
    static unsigned int x : 5;
};
int main() {}


Output: 

prog.cpp:5:29: error: static member 'x' cannot be a bit-field
     static unsigned int x : 5;
                             ^

5. Array of bit fields is not allowed. For example, the below program fails in the compilation. 

C




struct test {
    unsigned int x[10] : 5;
};
  
int main()
{
}


Output: 

prog.c:3:1: error: bit-field 'x' has invalid type
 unsigned int x[10]: 5; 
 ^

Most Asked Bit Field Interview Questions:

Predict the output of the following programs. Assume that unsigned int takes 4 bytes and long int takes 8 bytes. 

Question-1:

C




#include <stdio.h>
struct test {
    unsigned int x;
    unsigned int y : 33;
    unsigned int z;
};
int main()
{
    printf("%lu", sizeof(struct test));
    return 0;
}


Error:

./3ec6d9b7-7ae2-411a-a60e-66992a7fc29b.c:4:5: error: width of 'y' exceeds its type
     unsigned int y : 33;
     ^

 Question-2:

C




#include <stdio.h>
struct test {
    unsigned int x;
    long int y : 33;
    unsigned int z;
};
int main()
{
    struct test t;
    unsigned int* ptr1 = &t.x;
    unsigned int* ptr2 = &t.z;
    printf("%d", ptr2 - ptr1);
    return 0;
}


Output:

4

 Question 3:

Code block

Output:

t.x = 1, t.y = 1, t.z = 1

Please write comments if you find anything incorrect, or if you want to share more information about the topic discussed above.
 


My Personal Notes arrow_drop_up
Like Article
Save Article
Related Articles

Start Your Coding Journey Now!