Labels

Wednesday, June 9, 2010

Packing Bits with Bit Fields

Packing Bits C lets you pack bits tightly without requiring a lot of anding, and shifting. Lets assume we want to pack 4 values into one byte. These are a,b,c and d, defined like this.
 ddddcbaa
If we call this byte x then the value of d is
 d = (x >> 4) &0xf;
Which is a bit convoluted. What if we could just access the value of d and let the compiler do all the messy bit manipulation? Well we can but we have to define the bits using a bit field. To define our byte, we use a struct as follows.
 struct flagtype
{
unsigned char a: 2;
unsigned char b: 1;
unsigned char c : 1;
unsigned char d : 4;
};

struct flagtype f;

int x;
x=f.d; // fetch value
The values such as : 4 define how big each field is in bits. The type makes it a bit more complicated as it affects the position of the bits in the struct. Change b to an int and flagtype increases in size from 1 byte to 12! Change a as as well to an int though and flagtype shrinks to 8 bytes! This suggests that it is organizing the bits to start on a 4 byte boundary, presumably for optimal access speed. My guess is that it is something like this when a is a char and b an int:
 00000000 
00000000
00000000
000ddddc
00000000
00000000
00000000
0000000b
00000000
00000000
00000000
000000aa
Change a to an int as well and it all fits in 8 bytes like this:
 00000000 
00000000
00000000
000ddddc
00000000
00000000
00000000
00000baa
The actual layout implementation is probably compiler dependant. On Visual C++ 6, flagtype as declared is exactly one byte in size. Example 6 uses a union to access a variable of type flagtype. By assigning values to a,b,c etc, you can identify the layout of the bits.


ex:
#include 


struct flagtype
{
unsigned char a: 2;
unsigned int b: 1;
unsigned char c : 1;
unsigned char d : 4;
};

union utype {
struct flagtype f;
unsigned char byte;
};


int main(int argc, char* argv[])
{
union utype u;
int x;
u.byte=0;
printf("Size of u = %d\n",sizeof(u));
u.f.a=3;
u.f.b=0;
u.f.c=0;
u.f.d=15;
printf("Byte = %d",u.byte);
x=u.f.d;
return 0;}
}

1 comment: