The Benefits of Using c bit

25 Mar.,2024

 

chenlv Product Page

If you want to learn more, please visit our website chenlv.

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. C Bit fields are used when the storage of our program is limited.

Need of Bit Fields in C

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

Declaration of C Bit Fields

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 of C Bit Fields

struct
{
    data_type member_name : width_of_bit-field;
};

where,

  • 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_of_bit-field: The number of bits in the bit-field. The width must be less than or equal to the bit width of the specified type.

Applications of C 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.

Example of C Bit Fields

In this example, we compare the size difference between the structure that does not specify bit fields and the structure that has specified bit fields.

Structure Without Bit Fields

Consider the following declaration of date without the use of bit fields.

C

#include <stdio.h>

 

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.

Structure with Bit Field

The below code defines a structure named date with a single member month. The month member is declared as a bit field with 4 bits.

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, something interesting can happen.

Below is the same code but with signed integers:

C

#include <stdio.h>

 

struct date {

    

    

    int d : 5;

 

    

    

    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

Explanation

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 C Bit Fields

1. A special unnamed bit field of size 0 is used to force alignment on the next boundary.

Example: The below code demonstrates how to force alignment to the next memory boundary using bit fields.

C

#include <stdio.h>

 

struct test1 {

    unsigned int x : 5;

    unsigned int y : 8;

};

 

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.

Example: The below code demonstrates that taking the address of a bit field member directly is not allowed.

C

#include <stdio.h>

struct test {

    unsigned int x : 5;

    unsigned int y : 5;

    unsigned int z;

};

int main()

{

    struct test t;

 

    

    

    printf("Address of t.x is %p", &t.x);

 

    

    

    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.

Example: The below code demonstrates the usage of bit fields within a structure and assigns an out-of-range value to one of the bit field members.

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. Array of bit fields is not allowed.

Example: The below C program defines an array of bit fields and fails in the compilation.

C

#include <stdio.h>

 

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

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

Ans:

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;
     ^

 Q2. Predict the output of the following program.

Ans:

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

Q3. Predict the output of the following program.

Ans:

C

#include <stdio.h>

 

union test {

    

    unsigned int x : 3;

    

    unsigned int y : 3;

    

    int z;

};

 

int main()

{

    

    union test t;

    

    t.x = 5;

    

    t.y = 4;

    

    t.z = 1;

    

    printf("t.x = %d, t.y = %d, t.z = %d", t.x, t.y, t.z);

 

    return 0;

}


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



Last Updated :

08 Jun, 2023

Like Article

Save Article

Share your thoughts in the comments

Please to comment...

$\begingroup$

Advantage

Packing data is possible, both to the compiler and the user. An extreme example of this are u1 ints, a.k.a, booleans (as one bit unsigned integer has only two possible representations).

So if your language is focused or has an option to optimize to size (code or memory), this can be relevant. You can possibly pack 8 sequential booleans in a octec, instead of 8 sequential int_fast_t (the performante choice) that in some machines will be wasteful as 8x64 = 512 bits.

Disadvantage 1: slow

It will be slow. To the point that the users complain about it.

Modern languages gives integers that are power of two, multiple of octets because modern CPUs have them. And because CPUs have then, they are fast. As in hardware fast. As in there is nothing more fast than this is possible fast. And users like that.

Disadvantage 2: trashed on multithread

You may encounter situations where your compiler (or someone compilers) do the packing sometimes, but sometimes not. The problem with packed data is that CPUs may don't have how to write on packed data in an atomic way. The CPU will need to load the whole word, bitfidle it to simulate the partial write, and write back the whole memory world.

So, sometimes an a.b = true; in one thread, a.c = false; in another, in a packed struct, will result in impossible to reason results, another name for undefined behaviour.

The Benefits of Using c bit

What are the advantages of having a set number of fixed sized integers versus defining the exact number of bits in every integer?

View Details

Check now