Marco_D
Marco_D

Reputation: 95

Storing data in a variable through bits manipulation

I'm trying to store a date in an unsigned int variable, i need to store the date in this way:

Storing the year it's not a problem, since i do this:

unsigned int year=0;
year=year|2016

But then i have no idea i should put the month and the day. How can i put a number like 10 in the bits from 12 to 15 supposing bit 12 have value 1, bit 13 value 2 etc..

Wich strategy should i use?

Upvotes: 3

Views: 1528

Answers (2)

AdminXVII
AdminXVII

Reputation: 1329

In C, you can shift bits both ways using a >> b or a << b where a is the number to shift and b is the number of shifts. The bits inserted will be 0s.

In your case, it would be

unsigned int time=0;
time |= year;
time |= month << 12;
time |= day << 16;

To unpack it, you simply have to shift time in the other direction and & it to the number of wanted bits:

int year = time & 0b111111111111;
int month = (time >> 12) & 0b1111;
int day = (time >> 16) & 0b11111;

EDIT

If you want the data to be ordered from the most significant bit and stacked to it

ex:

 11111111111111111111100000000000
 \___________|___|___/
      year  month day

you just need to shift the data accordingly

PACK:

short int_length = sizeof(unsigned int); //usually 32
unsigned int time=0;
time |= year << (int_length - 12);
time |= month << (int_length - 16);
time |= day << (int_length - 21);

UNPACK:

short int_length = sizeof(unsigned int); //usually 32
int year = (time >> (int_length - 12)) & 0b111111111111;
int month = (time >> (int_length - 16)) & 0b1111;
int day = (time >> (int_length - 21)) & 0b11111;

If you want the data to be ordered from the most significant bit and stacked to the least significant bit

ex:

 00000000000111111111111111111111
            \___________|___|___/
                  year  month day

Use instead this

PACK:

unsigned int time=0;
time |= year << 9;
time |= month << 5;
time |= day;

UNPACK:

int year = (time >> 9) & 0b111111111111;
int month = (time >> 5) & 0b1111;
int day = time & 0b11111;

Upvotes: 5

David C. Rankin
David C. Rankin

Reputation: 84642

As others have mentioned, you may find a bitfield easier to work with than shifting and or'ing to align the bits. A bitfield is declared as a normal structure, but allows segregating bits between the members of the structure. For your year, month, day, you could use something similar to:

typedef struct {    /* bitfield for year, month, day */
    unsigned    year : 11,
                mon  :  4,
                day  :  4;
} datebits;

The datebits struct segregates the first 11 bits for the year, the next 4 for the month, and the final 4 for the day. You use it just like any other struct. Here is a short example:

#include <stdio.h>

typedef struct {    /* bitfield for year, month, day */
    unsigned    year : 11,
                mon  :  4,
                day  :  4;
} datebits;

typedef union {     /* union to avoid violating strict aliasing    */
    datebits d;     /* when shifting datebits to print binary bits */
    unsigned u;     /* (this is only for putchar bit output)       */
} duu;

int main (void) {

    unsigned i = 19;
    datebits d;     /* declare bitfield */
    duu du;

    d.year = 1999;  /* fill bitfield */
    d.mon  = 12;
    d.day  = 2;

    du.d = d;

    printf ("\n year : %u  month : %u  day : %u\n\n (bits in memory) d : ",
            d.year, d.mon, d.day);

    while (i--)     /* verification of each bit in memory */
        putchar ((du.u >> i) & 1 ? '1' : '0');
    putchar ('\n');

    return 0;
}

Output

$ ./bin/bitfield_datebits

 year : 1999  month : 12  day : 2

 (bits in memory) d : 0010110011111001111

(note: the union is just to facilitate the binary printing of the individual bits, it is not needed for normal use of datebits).

As you can see your day is 0010, your month 1100 and the year 11111001111 in proper order.

Upvotes: 2

Related Questions