Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bit shifting masks still elude me

Could someone please take a look at this sloppy code and explain to me why it does not work. Am I packing and unpacking things correctly? (the object of this lab was to pack a date using bit shifting and masking. For example console input of 31/12/99 would be OR'ed together then AND'ed out, which is what my code was attempting to do. Thanks.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define DAY_MASK 0x3e0
#define MONTH_MASK 0xc00
#define YEAR_MASK (~0x3180)

void hr()
{
    printf("-----------------------------------------------\n");
}

void fields()
{
    printf("     Binary\t\tDTG\t\tBase 10\n");
}

void prnFields(unsigned int *day, unsigned int *month, unsigned int *year)
{
    printBits(day);
    printf("\tDay\t\t%u\n", day);
    printBits(month);
    printf("\tMonth\t\t%u\n", month);
    printBits(year);
    printf("\tYear\t\t%u\n", year);
}

int main()
{
    unsigned int day;
    unsigned int month;
    unsigned int year;
    unsigned int packed;

    printf("Enter numeric Day\t:");
    scanf("%d", &day);
    printf("Enter numeric Month\t:");
    scanf("%d", &month);
    printf("Enter two digit Year\t:");
    scanf("%d", &year);
    printf("\n");

    hr();
    printf("\nPrepacked Date\n");
    fields();
    hr();
    prnFields(day, month, year);
    hr();

    packed = day; packed <<= 9;
    packed |= month; packed <<= 4;
    packed |= year;
    printf("\nPacked Date\n");
    fields();
    hr();
    printBits(packed);printf("\t\t\t%d\n", packed);
    hr();
    printf("\nUnpacked Date\n");
    fields();
    hr();
    printBits((packed & DAY_MASK));
    printf("\tDay\t\t%d \n", (packed & DAY_MASK) >> 9);
    printBits((packed & MONTH_MASK));
    printf("\tMonth\t\t%d \n", (packed & MONTH_MASK) >> 5);
    printBits((packed & YEAR_MASK));
    printf("\tYear\t\t%d \n", (packed & YEAR_MASK));
     //system("pause");
    return(0);
}

void printBits(unsigned short int value)
{
    unsigned short int mask =1;
    int i;
    mask<<=15;

    for(i=1; i<=16; i++)
    {
        putchar( (mask&value)? '1': '0');

        if(i%8==0)
        {
            putchar(' ');
        }

        value<<=1;
    }
}
like image 868
David Avatar asked Jan 20 '12 04:01

David


1 Answers

You seem to have too few bits assigned for Month (0xc00) and the way you do it it's not easy to see whether your shifts are correct.

I'd suggest to define your constants in a more consistent way like this:

#define DAY_BITS   5
#define MONTH_BITS 4
#define YEAR_BITS  7

#define DAY_OFFSET   YEAR_BITS
#define MONTH_OFFSET ( YEAR_BITS + DAY_BITS )
#define YEAR_OFFSET  0

#define DAY_MASK   ~( ~0 << DAY_BITS   )
#define MONTH_MASK ~( ~0 << MONTH_BITS )
#define YEAR_MASK  ~( ~0 << YEAR_BITS  )

... now you can set the packed value like this:

packed = 0;
packed |= ( day   & DAY_MASK   ) << DAY_OFFSET;
packed |= ( month & MONTH_MASK ) << MONTH_OFFSET;
packed |= ( year  & YEAR_MASK  ) << YEAR_OFFSET;

... and get the single fields like this:

printf("\tDay\t\t%d \n",   ( packed >> DAY_OFFSET   ) & DAY_MASK );
printf("\tMonth\t\t%d \n", ( packed >> MONTH_OFFSET ) & MONTH_MASK );
printf("\tYear\t\t%d \n",  ( packed >> YEAR_OFFSET  ) & YEAR_MASK );

You could now simply change the order of the fields in your offset definitions to make the dates easily sortable:

#define DAY_OFFSET   0
#define MONTH_OFFSET DAY_BITS
#define YEAR_OFFSET  ( DAY_BITS + MONTH_BITS )
like image 167
x4u Avatar answered Oct 28 '22 20:10

x4u