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





4.00/5 (1 vote)
Mar 6, 2002
1 min read

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!)