Converting big endian structures to little endian
I'm making a C program that communicates with a patient monitor that uses big endian byte ordering. For example, if I've certain C structure
typedef struct {
int short a;
int short b;
int c;
} msg;
To read this kind of structure, I can simply use ntohs(msg.a), ntohs(msg.b), ntohl(msg.c). But some of the structure has a buffer of short integers but that buffer itself is type of an another structure. For example,
typedef struct {
int short length;
int short b[MAX_BUF_SIZE];
} msg1;
The field "b" in above structure represents an another structure, which is below:
typedef struct {
int short a;
int short b;
} msg2;
Now, my question is 1) should I convert all the short integers of structure "msg1" to host order and then cast it to pointer of type "msg2" and simply read "msg2.a" and "msg2.b" or 2) I should convert the byte ordering of "msg2.a" and "msg2.b" as well or 3) just cast "msg1.b" to pointer of type "msg2" and read "msg2.a" and "msg2.b" by converting each of them to host order?
Please tell which one of the approach is correct to read msg1
APPROACH 1
int t[msg1.length];
for(int i = 0; i < msg1.length; i++)
t[i] = ntohs(*(msg1.b + i));
msg2 * msg2_m = (msg2 *)t;
/* should I convert the msg2_m.a and msg2_m.b as well? */
printf("%d:%d", msg2_m.a, msg2_m.b);
APPROACH 2
All same except
printf("%d:%d", ntohs(msg2_m.a), ntohs(msg2_m.b));
APPROACH 3
Not converting "msg1.b" and directly casting "msg1.b" to "msg2" and just convert "msg2.a" and "msg2.b" to host order.
msg2 *msg2_m = (msg2 *)msg1.a;
printf("%d:%d", ntohs(msg2_m.a), ntohs(msg2_m.b));
I need to understand when a structure is casted to some other structures does its byte ordering are changed according to the new structure when passed across network? I think APPROACH 3 is correct, but thats just me, I'm not sure about internals of byte ordering. Any help would be appreciated.
Thanks, Shivam Kalra
First, casting does not affect byte order.
Second, you don't want to be thinking about byte order everywhere in your code because you or someone else will forget and make a mistake somewhere and it will be hell trying to find the bug later. So, as soon as you read the data in, convert it to the correct byte order. If you read a struct in that contains an array of shorts, convert the whole array of shorts to the correct byte order immediately. The same goes for any other structs. Convert the data and store the result; don't just use ntohs each time you need to read or print something. Segregate this code from the rest of your program so that you can forget about byte order in the other parts of the program and only think about byte order when you're dealing with the conversion code.
I think it's usually better not to try to read or write struct
s directly. Instead, you should explicitly define your wire format and write your struct byte-by-byte to that (and then do the reverse when reading). For example, to write:
typedef struct {
short int a;
short int b;
int c;
} msg;
you can do:
void WriteBigEndian16(uint16_t x, FILE* fp)
{
fputc((x >> 8) & 0xFF, fp);
fputc( x & 0xFF, fp);
}
void WriteBigEndian32(uint32_t x, FILE* fp)
{
fputc((x >> 24) & 0xFF, fp);
fputc((x >> 16) & 0xFF, fp);
fputc((x >> 8) & 0xFF, fp);
fputc( x & 0xFF, fp);
}
FILE* fp = fopen(...);
msg m; // Assume that this is initialized.
WriteBigEndian16(m.a, fp);
WriteBigEndian16(m.b, fp);
WriteBigEndian32(m.c, fp);
This has the advantages of:
struct
s are byte-swapped or not. They will always be whatever the platform's native ordering is. int
? 上一篇: 用C语言编写Socket并反序列化响应
下一篇: 将大端结构转换成小端