3

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

  • Bits 11 to 0 for the year (from 0 to 4095)
  • Bits 15 to 12 for the month (as if they were bits from 0 to 3, so I can store value from 0 to 11)
  • Bits 20 to 16 for the day (0-31)

Storing the year is 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..

Which strategy should I use?

6
  • 2
    Learn about bit operators. Commented Feb 22, 2016 at 23:29
  • Shift to align each field. Commented Feb 22, 2016 at 23:32
  • or to use a struct unioned with a uint32 Commented Feb 22, 2016 at 23:49
  • @BLUEPIXY: The order of bits in a bit-field is implementation defined. It is therefore not ensured that the result has the desired layout. Commented Feb 22, 2016 at 23:59
  • 1
    Voting to close this question because OP seems to want year be in the most significant bits but failed to express it in the question. Commented Feb 23, 2016 at 2:38

2 Answers 2

5

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;
Sign up to request clarification or add additional context in comments.

5 Comments

Do this will move all the bits? in this case i'll not be able to recover the year or the month from the value
Yeah you need also tell how to unpack the data.
But in this case the bits are not in the way i need
I don't mean to be a nit, but for the sake of completeness, the bit mask constants in your second block should be prefixed with 0b
@Marco_D please clarify why this is not what you wanted. When talking about bits, "first" and "last" is confusing. In machine terms "first bit" means bit 0 which is the lowest bit. Programmers usually follow this convention. If you want year to be placed to the "top" or "most significant" bits then please edit the question to reflect such.
2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.