# Bit Fields in C

In C, we can specify size (in bits) of structure and union members. The idea 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 withing a small range.

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

`#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); ` `} ` |

*chevron_right*

*filter_none*

**Output:**

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

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

`#include <stdio.h> ` ` ` `// Space optimized representation of the date ` `struct` `date { ` ` ` `// d has value between 1 and 31, so 5 bits ` ` ` `// are sufficient ` ` ` `unsigned ` `int` `d : 5; ` ` ` ` ` `// m has value between 1 and 12, so 4 bits ` ` ` `// are sufficient ` ` ` `unsigned ` `int` `m : 4; ` ` ` ` ` `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); ` ` ` `return` `0; ` `}` |

*chevron_right*

*filter_none*

**Output:**

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

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:

`#include <stdio.h> ` ` ` `// Space optimized representation of the date ` `struct` `date { ` ` ` `// d has value between 1 and 31, so 5 bits ` ` ` `// are sufficient ` ` ` `int` `d : 5; ` ` ` ` ` `// m has value between 1 and 12, 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; ` `}` |

*chevron_right*

*filter_none*

**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 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 4-bit representation as 1100 which on calculating 2’s complement you get the value of -4.

**Following are some interesting facts about bit fields in C.**

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

`#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; ` `}` |

*chevron_right*

*filter_none*

**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.

`#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; ` `} ` |

*chevron_right*

*filter_none*

**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.

`#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; ` `} ` |

*chevron_right*

*filter_none*

**Output:**

Implementation-Dependent

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

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

*chevron_right*

*filter_none*

**Output:**

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

*chevron_right*

*filter_none*

**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.

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

*chevron_right*

*filter_none*

**Output:**

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

**Exercise:**

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

**1)**

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

*chevron_right*

*filter_none*

**2)**

`#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; ` `} ` |

*chevron_right*

*filter_none*

3)

`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; ` `} ` |

*chevron_right*

*filter_none*

**4)** Use bit fields in C to figure out a way whether a machine is little-endian or big-endian.

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

## Recommended Posts:

- Bitwise AND of all the odd numbers from 1 to N
- Difference between Increment and Decrement Operators
- Find Kth smallest value for b such that a + b = a | b
- Problem in comparing Floating point numbers and how to compare them correctly?
- exit(0) vs exit(1) in C/C++ with Examples
- Construct XOR tree by Given leaf nodes of Perfect Binary Tree
- Generating N-bit Grey Code starting from K
- Check if all bits can be made same by flipping two consecutive bits
- Maximize distance between any two consecutive 1's after flipping M 0's
- Find the sum of power of bit count raised to the power B
- Maximum XOR value of maximum and second maximum element among all possible subarrays
- Append two elements to make the array satisfy the given condition
- Find the number obtained after concatenation of binary representation of M and N
- Invert the Kth most significant bit of N