65.9K
CodeProject is changing. Read more.
Home

Structure Bit Ordering : Using ntoh and hton when transfering data between different platforms

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (1 vote)

Mar 6, 2002

1 min read

viewsIcon

82657

Some traps to lookout when packing bits into a structure

Introduction

I have a 4-byte data, which is defined as:

Bits 31-24 Bits 21-23 Bit 20 Bit 19-10 Bit 9-0
Pixel Data Spare set to 0 Direction Pixel Y address (row) Pixel X address (col)

When using MS compiler on intel PC, its rule is: bit fields are laid out from the least significant bit to the most significant bit. So in my VC++ code, I define the structure as:

#pragma pack(1)
typedef struct
{
    unsigned int pixel_y_address : 10; // bits 0 - 9
    unsigned int pixel_x_address : 10; // bits 10 - 19
    unsigned int direction : 1; // bits 20
    unsigned int unused : 3; // bits 21-23
    unsigned int pixel_data : 8; // bits 24 - 31
} Image_Segment_Data;

Now I need to transfer these data to my program running on PowerPC. The operating system here is VxWorks. I found out that the rule here is reversed comparing with MS compiler: bit fields are laid out from the most significant bit to the least significant bit. So in my VxWorks code, I define the structure as:

struct image_segment_data_
{
    unsigned int pixel_data : 8; /* bits 24 - 31 */
    unsigned int unused : 3; /* bits 21-23 */
    unsigned int direction : 1; /* bits 20 */
    unsigned int pixel_x_address : 10; /* bits 10 - 19 */
    unsigned int pixel_y_address : 10; /* bits 0 - 9 */
} __attribute__ ((packed));

typedef image_segment_data_ Image_Segment_Data;

But the story does not stop here. When sending out data using TCP/IP socket, the MSB in PC code is received as LSB in VxWorks code. That is, data from PC {pppp,pppp,uuud,xxxx,xxxx,xxyy,yyyy,yyyy} is parsed by VxWorks as {yyyy,yyyy,xxxx,xxyy,uuud,xxxx,pppp,pppp}. What a hell! This is because the host byte order is not the same on these two platforms. So the data must be converted before sent by PC. To facilitate this, a union is defined as:

typedef union
{
    Image_Segment_Data data;
    unsigned long raw;
} Image_Segment_Union;
The reversing is easy:
Image_Segment_Data  originData;
Image_Segment_Union originUnion;
Image_Segment_Union tempUnion;

when sending from PC:
originUnion.data = originData;
tempUnion.raw = htonl(originUnion.raw) ;
send(sd, (char *)&tempUnion.raw, sizeof(tempUnion.raw), 0);

when receiving from PowerPC:
recv(sd, (char *)&tempUnion.raw, sizeof(tempUnion.raw));
originUnion.raw = ntohl(tempUnion.raw);
originData = originaUnion.data

Conclusion

That’s all I figured out. Thank you, Time Finer and axiac, for pointing out my mistake on understanding this issue.

Reference: Joaquín M López Muñoz’s answer to my question "Help! About structure alignment". (No wonder I love CP so much!)