【问题标题】:How to do Endian conversion when dealing with bit fields处理位域时如何进行字节序转换
【发布时间】:2021-05-26 14:27:52
【问题描述】:

我正在处理需要通过我自己(客户端)和服务器之间的 TCP/IP 套接字发送/接收数据的情况。消息结构是专有的,但基本上是 uint32_t 数组。我的任务是最终处理 Endian 转换。作为客户端,我在 Windows(小端)中操作。服务器在 VxWorks 环境(大端)中运行。因此,我需要将发送的数据从小转换为大,将接收的数据从大转换为小。

现在,我知道字节顺序是指单词中的字节顺序。因此,我创建了一个函数,该函数将为给定数组中的每个 uint32_t 字进行字节交换。见下文。

void convertEndian(uint32_t inputData[], int size)
{
    uint32_t b1, b2, b3, b4;

    for (int i = 0; i < size; ++i)                                                               
    {
        b1 = (inputData[i] & 0xFF000000) >> 24;
        b2 = (inputData[i] & 0x00FF0000) >> 8;
        b3 = (inputData[i] & 0x0000FF00) << 8;
        b4 = (inputData[i] & 0x000000FF) << 24;
        
        inputData[i] = b1 | b2 | b3 | b4;
    }
}

这种方法适用于我将要处理的某些消息类型,其中每个单词都由整个 uint32_t 值定义。然而,有些消息有很多词,它们有自己独特的位域。下面是一个例子:

Struct test
{
                Unsigned int var1 : 16;
                Unsigned int var2 : 12;
                Unsigned int var3 : 1;
                Unsigned int var4 : 1;
                Unsigned int var5 : 1;
                Unsigned int var6 : 1;
}

在这种情况下如何实现字节序转换?例如,有一种消息类型,我将在其中接收大约 32 个 uint32_t 字的数组,每个字都有自己的一组位字段,代表各种事物。

我想我唯一的选择是根据需要对每个单词进行屏蔽/移位。但是接下来我几乎必须为每个单词创建 32 个独特的函数。这似乎很费力。

任何建议将不胜感激。

【问题讨论】:

  • 使用正确的序列化格式和库。
  • 另见this
  • 您能否确认消息中位域的布局?在 Big Endian 平台上,有一种约定从最重要的位开始布局位域,但这不是给定的。
  • 这就是人们使用网络字节顺序的原因,也是为什么通过现代网络发送原始二进制数据远不如过去常见的原因。

标签: c


【解决方案1】:

希望这没有太多的假设。

完全未经测试,幽默未标记。

static_assert(sizeof(test) == sizeof (uint32_t), "Houston we have a problem");

template < typename NetOrHost>
void convertEndian(uint32_t inputData[], int size) {
  for (int i = 0; i < size; ++i)            
    inputData[i] = NetOrHost(inputData[i]);
}

// or simply use

std::for_each(inputData, inputData+size, htonl /* ntohl for the other way */); // this part needs a bit of testing ...

// Now encoding the test struct
// Using https://stackoverflow.com/a/20194422/4013258 BitCount
// or just use magic values, *hands OP a foot-gun*

// Once only
std::array<int, 6> bits; // todo make this constexpr
bits[0] = BitCount(test.var1);
bits[1] = BitCount(test.var2);
etc ...
static_assert(std::accumulate(bits.begin(), bits.end(), 0) == 32, "Preconditions violated");

// this goes well because we know that it fits in a 32-bit unsigned integer.
uint32_t encoded = 0;

encoded = test.var1;
encoded <<= bits[1];
encoded += test.var2;
encoded <<= bits[2];
encoded += test.var3;
etc.

// To decode
uint32_t decode = inputData[i];

test.var6 = decode & ((1 << bits[5])-1); // or make a mask array
decode >>= bits[5];
etc.

使用反射会容易得多...

【讨论】:

  • 我应该注意这是针对 C 实现,而不是 C++
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-15
  • 2010-10-17
相关资源
最近更新 更多