c++ - 在 C++11 中实现现有的网络接口(interface),定义关于字节序的位域

标签 c++ c++11 boost endianness bit-fields

我目前正在为现有网络远程开发一个 C++11 库 接口(interface)控制文档 (ICD) 中描述的控制接口(interface)。

该接口(interface)基于 TCP/IPv4 并使用网络字节序(又名Big 字节序)。

要求:该库应跨平台开发。

注意:我想开发一个 (ab)使用预处理器的解决方案。

在 WWW 上进行了短暂的研究后,我发现了 Boost.Endian这解决了 与多字节数据类型的字节序相关的问题。我的方法是 如下:

  1. 通过以下方式将(多)字节数据类型序列化为流 std::basic_ostream::write ,更准确地说是通过 os.write(reinterpret_cast<char const *>(&kData), sizeof(kData)) .
  2. 转换 std::basic_ostreamstd::vector<std::uint8_t> .
  3. 发送std::vector<std::uint8_t>通过Boost.Asio通过网络。

到目前为止一切顺利。一切似乎都按预期工作,解决方案应该是 平台无关。

现在是棘手的部分:ICD 描述了由多个 字,一个字由 8 位组成。一条消息可以包含多个字段和一个 字段不必按字节对齐,这意味着一个字可以包含 多个字段。

示例:考虑以下消息格式(消息正文开始于 单词 10):

Word | Bit(s) | Name
-----|--------|----------
 10  |  0-2   |  a
 10  |   3    |  b
 10  |   4    |  c
 10  |   5    |  d
 10  |   6    |  e
 10  |   7    |  RESERVED
 11  |   16   |  f

等等……

所以现在我需要一个能够对基于位的接口(interface)进行建模和序列化的解决方案。

到目前为止,我已经研究了以下方法:

  1. Bit field
  2. std::bitset
  3. boost::dynamic_bitset

    • 1不是跨平台的(依赖于编译器)。
    • 23似乎可以使用 native 字节顺序(即 Little Endian 我的机器),所以下面的例子使用 boost::dynamic_bitset才不是 为我的场景工作:

代码:

// Using a arithmetic type from the `boost::endian` namespace does not work.
using Byte = std::uint8_t;
using BitSet = boost::dynamic_bitset<Byte>;
BitSet bitSetForA{3, 1};
BitSet bitSetForB{1};
// [...]
BitSet bitSetForF{16, 0x400}; // 1024

因此,上面示例中的 1024 总是序列化为 00 04代替 04 00在我的机器上。

我真的不知道解决我的问题最实用的方法是什么。 也许你可以引导我走向正确的方向。

总而言之,我确实需要一个配方来实现现有的网络接口(interface)定义位 以与平台无关的方式相对于 native 字节顺序的字段 编译库的机器。

最佳答案

最近有人好心地给我指了一个nice article about endianness我从中获得灵感。

std::bitset 有一个 to_ulong 方法,可用于返回位域的整数表示(字节序无关),下面的代码将打印您的输出以正确的顺序:

#include <iostream>
#include <iomanip>
#include <bitset>

int main()
{
  std::bitset<16> flags;
  flags[10] = true;
  unsigned long rawflags = flags.to_ulong();
  std::cout << std::setfill('0') << std::setw(2) << std::hex
            << (rawflags & 0x0FF) // little byte in the beginning                                                     
            << std::setw(2)
            << ((rawflags>>8) & 0x0FF) // big byte in the end                                                         
            << std::endl;
}

请注意,在这种情况下,使用位字段的解决方案不会轻易奏效,因为这些位也会在小端机器上交换!

例如在这样的结构中:

struct bits {
  unsigned char first_bit:1;
  unsigned char rest:7;
};
union {
  bits b;
  unsigned char raw;
};

将 b.fist_bit 设置为 1 将导致原始值为 1 或 128,具体取决于字节顺序!

HTH

关于c++ - 在 C++11 中实现现有的网络接口(interface),定义关于字节序的位域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30201877/

相关文章:

没有 typedef 的模板类的 C++ 模板,这可能吗?

c++ - 在 Visual Studio 2012 中链接 zlib

c++ - 在多作者情况下如何对文件支持的共享内存中的大页进行故障处理

c++ - 使用 constexpr initializer_list 构造函数时 MSVC 无法编译

c++ - 是否可以从字符串创建可变参数元组?

c++ - 函数的嵌套 C++ 模板参数

c++ - 如何从 vector<string> 中提取第一个元素并在循环中将 vector 大小减少 1

c++ - Boost 库在 Windows 上未正确链接

visual-c++ - 使用 boost 和 Visual C++ 2005 解压缩 zip 文件?

c++ - 如何重置 boost::sml::sm 实例