c++ - 二进制协议(protocol) - 字节交换技巧

标签 c++ c

假设我们有一个二进制协议(protocol),其中的字段按网络顺序排列(大端)。

struct msg1
{
    int32 a;
    int16 b;
    uint32 c
}

如果不是将网络缓冲区复制到我的 msg1,然后使用“networkToHost”函数读取 msg1

我将 msg1 重新排列/反转为

struct msg1
{
    uint32 c
    int16 b;
    int32 a;
}

然后简单地从网络缓冲区做一个反向复制来创建 msg1。在这种情况下,不需要 networkToHost 函数。这种惯用的方法在大端机器上不起作用,但对我来说这不是问题。除此之外,还有其他我想念的缺点吗?

谢谢

附言对于以上内容,我们强制执行严格对齐(#pragma pack(1) 等)

最佳答案

除此之外,还有其他我想念的缺点吗?

恐怕您误解了端序转换问题的本质。 “Big endian”并不意味着您的字段是反向排列的,因此

struct msg1_bigendian
{
    int32 a;
    int16 b;
    uint32 c
}

在大端架构上相当于一个

struct msg1_littleendian 
{
   uint32 c;
   int16 b;
   int32 a;
}

关于小端架构。相反,它意味着每个字段中的字节顺序 是相反的。让我们假设:

a = 0x1000000a;
b = 0xb;
c = 0xc;

在大端架构上,这将被布局为:

10 00 00 0a
00 0b
00 00 00 0c

高阶(最重要的)字节在前。

在小端机器上,这将被布局为:

0a 00 00 10
0b 00
0c 00 00 00

最低位在前,最高位在后。

序列化它们并将消息的序列化形式叠加在一起,您会发现不兼容:

10 00 00 0a  00 0b  00 00 00 0c (big endian)
0a 00 00 10  0b 00  0c 00 00 00 (little endian)

   int32 a  int16 b    int32 c

请注意,这不仅仅是字段反向运行的情况。你的提议会导致小端机器将大端表示误认为是:

a = 0xc000000; b = 0xb00; c = 0xa000010;

当然不是传输的内容!

对于传输的每个字段,您确实必须将每个单独的字段转换为网络字节顺序,然后再转换回来。

更新:

好的,我明白你现在想做什么了。您想要反向定义结构,然后从字节字符串的 end 到开头进行 memcpy(反向复制)并以这种方式反转字节顺序。在这种情况下,我会说,是的,这是一个 hack,是的,它使您的代码不可移植,是的,这是不值得的。事实上,字节顺序之间的转换并不是一个非常昂贵的操作,而且它比反转每个结构的布局更容易处理。

关于c++ - 二进制协议(protocol) - 字节交换技巧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/646842/

相关文章:

c - 为什么默认的 SIGPIPE 处理程序被更改?

c++ - 同时多次运行一个进程

c - C 中的 "write"系统调用无法识别来自 "read"系统调用的随机整数

c++ - 在固定模板参数的同时扩展模板类

c++ - 如何在 C++ 多平台中将 (char *) 从 ISO-8859-1 转换为 UTF-8?

c - 如何将 $CC 中的 "implicit declaration"警告变成错误?

检查共享内存上的新输入

C - sprintf 打印变量名

c++ - 使用构造函数参数初始化结构数组

c++ - 将 `extern template` 与第三方仅 header 库一起使用