Although the question was asked a long time ago, there is no answer explaining your result. I will answer it, I hope it will be useful to someone.
I will illustrate the error using the first 16 bits of your data structure.
Please note: this explanation is guaranteed only with the set of your processor and compiler. Any of these changes may change behavior.
Fields:
unsigned int ver : 4; unsigned int hlen : 4; unsigned int stype : 8;
Assigned:
dgram.ver = 4; dgram.hlen = 5; dgram.stype = 0;
The compiler begins to assign bit fields, starting at offset 0. This means that the first byte of your data structure is stored in memory as:
Bit offset: 7 4 0 ------------- | 5 | 4 | -------------
The first 16 bits after assignment are as follows:
Bit offset: 15 12 8 4 0 ------------------------- | 5 | 4 | 0 | 0 | ------------------------- Memory Address: 100 101
You use an Unsigned 16 pointer for the dereference memory address 100. As a result, address 100 is treated as the low-order bit of a 16-bit number. And 101 is seen as an MSB 16-bit number.
If you type * ptr in hexadecimal, you will see the following:
*ptr = 0x0054
Your loop runs on this 16-bit value and therefore you get:
00000000 0101 0100 -------- ---- ---- 0 5 4
Solution: Reorder items to
unsigned int hlen : 4; unsigned int ver : 4; unsigned int stype : 8;
And use an unsigned char * pointer to move and print values. It should work.
Note that, as others have said, this behavior is platform and compiler specific. If any of these changes you need to verify the layout of your data structure.