将大端结构转换为小端

时间:2012-01-20 00:05:51

标签: c networking endianness

我正在制作一个与使用大端字节排序的患者监视器通信的C程序。例如,如果我确定C结构

typedef struct {
   int short a;
   int short b;
   int       c;
} msg;

要阅读这种结构,我可以简单地使用ntohs(msg.a),ntohs(msg.b),ntohl(msg.c)。但是一些结构具有短整数缓冲区,但缓冲区本身是另一种结构的类型。例如,

typedef struct {
   int short length;
   int short b[MAX_BUF_SIZE];
} msg1;

上述结构中的字段“b”表示另一种结构,如下所示:

typedef struct {
   int short a;
   int short b;
} msg2;

现在,我的问题是1)我应该将结构“msg1”的所有短整数转换为主机顺序,然后将其转换为“msg2”类型的指针,只需读取“msg2.a”和“msg2.b”或者2)我应该转换“msg2.a”和“msg2.b”的字节顺序或3)只是转换 “msg1.b”指向“msg2”类型的指针,并通过将每个指针转换为主机顺序来读取“msg2.a”和“msg2.b”?

请告诉我们哪种方法是正确的,以便阅读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

之外的所有相同内容
printf("%d:%d", ntohs(msg2_m.a), ntohs(msg2_m.b));

APPROACH 3

不转换“msg1.b”并直接将“msg1.b”转换为“msg2”,只需将“msg2.a”和“msg2.b”转换为主机订单。

msg2 *msg2_m = (msg2 *)msg1.a;
printf("%d:%d", ntohs(msg2_m.a), ntohs(msg2_m.b));

我需要了解何时将结构转换为某些其他结构时,其字节顺序是否会在通过网络时根据新结构进行更改?我认为APPROACH 3是正确的,但那只是我,我不确定字节排序的内部。任何帮助将不胜感激。

谢谢, Shivam Kalra

2 个答案:

答案 0 :(得分:3)

首先,强制转换不会影响字节顺序。

其次,您不希望在代码中的任何地方考虑字节顺序,因为您或其他人忘记并在某处犯错误,以后它会试图找到该错误。因此,只要读入数据,就将其转换为正确的字节顺序。如果您读取包含short数组的结构,请立即将整个short数组转换为正确的字节顺序。任何其他结构都是如此。转换数据并存储结果;每次你需要阅读或打印东西时,不要只使用ntohs。将此代码与程序的其余部分隔离开来,这样您就可以忘记程序其他部分的字节顺序,只考虑处理转换代码时的字节顺序。

答案 1 :(得分:2)

我认为通常最好不要直接尝试读写struct。相反,您应该明确定义有线格式并逐字节地写入结构(然后在读取时反向执行)。例如,写:

typedef struct {
   short int a;
   short int b;
   int       c;
} msg;

你可以这样做:

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

这有以下优点:

  • 代码与endian无关。如果你在小端机器或大端机器上运行并不重要。你不需要知道。
  • 您可以避免对内存中struct是否进行字节交换产生混淆。它们将永远是平台的原生订单。
  • 您也在定义字段的大小。如果您没有定义电线格式,不仅容易出现字节序不匹配,而且容易出现尺寸不匹配的情况。谁说这两个端点对int使用相同的大小?