Reputation: 95
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
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
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