Bitfield and Union - unexpected result in C

Viewed 2591

I've been given the following assignment in a C-course:

enter image description here

I've implemented the assignment to decode the 8 byte long long int 131809282883593 as follows:

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

    struct Message {
         unsigned int hour : 5;
         unsigned int minutes : 6;
         unsigned int seconds : 6;
         unsigned int day : 5;
         unsigned int month : 4;
         unsigned int year : 12;
         unsigned long long int code : 26;
    };  // 64 bit in total

    union Msgdecode {
        long long  int datablob;
        struct Message elems;
    };

    int main(void) {

        long long int datablob = 131809282883593;
        union Msgdecode m;

        m.datablob = datablob;

        printf("%d:%d:%d %d.%d.%d code:%lu\n", m.elems.hour, m.elems.minutes,
        m.elems.seconds, m.elems.day, m.elems.month, m.elems.year,(long unsigned int) m.elems.code); 

        union Msgdecode m2;
        m2.elems.hour = 9;
        m2.elems.minutes = 0;
        m2.elems.seconds = 0;
        m2.elems.day = 30;
        m2.elems.month = 5;
        m2.elems.year = 2017;
        m2.elems.code = 4195376;

        printf("m2.datablob: should: 131809282883593 is: %lld\n", m2.datablob); //WHY does m2.datablob != m.datablob?! 
        printf("m.datablob:  should: 131809282883593 is: %lld\n", m.datablob);

        printf("%d:%d:%d %d.%d.%d code:%lu\n", m2.elems.hour, m2.elems.minutes,
          m2.elems.seconds, m2.elems.day, m2.elems.month, m2.elems.year, (long unsigned int) m2.elems.code);

    }

TRY IT ONLINE.

..what gives me a hard time is the output. The decoding/encoding works nicely so far. 9:0:0 30.5.2017 and code 4195376 is expected, but the difference in the 'datablob' really isn't - and i can't figure out why/where it stems from:

9:0:0 30.5.2017 code:4195376
m2.datablob: should: 131809282883593 is: 131810088189961
m.datablob:  should: 131809282883593 is: 131809282883593
9:0:0 30.5.2017 code:4195376

As you can see the datablob is close to the original - but not the original. I've consulted a coworker whos fluent in C about this - but we couldn't figure out the reason for this behaviour.

Q: Why do the blobs differ from each other?

Bonus-Q: When manipulating the union Msgdecode to include another field, a strange thing happens:

union Msgdecode {
    long long  int datablob;
    struct Message elems;
    char bytes[8];  // added this
};

Outcome:

9:0:0 30.5.2017 code:0
m2.datablob: should: 131809282883593 is: 8662973939721
m.datablob:  should: 131809282883593 is: 131809282883593
9:0:0 30.5.2017 code:4195376

PS: reading on SO about bitfields+union questions gave me the impression that they are rather unreliable. Can this be generally said?

3 Answers
Related