我目前正在为现有网络远程开发一个 C++11 库 接口(interface)控制文档 (ICD) 中描述的控制接口(interface)。
该接口(interface)基于 TCP/IPv4 并使用网络字节序(又名Big 字节序)。
要求:该库应跨平台开发。
注意:我想开发一个不 (ab)使用预处理器的解决方案。
在 WWW 上进行了短暂的研究后,我发现了 Boost.Endian这解决了 与多字节数据类型的字节序相关的问题。我的方法是 如下:
- 通过以下方式将(多)字节数据类型序列化为流
std::basic_ostream::write ,更准确地说是通过
os.write(reinterpret_cast<char const *>(&kData), sizeof(kData))
. - 转换
std::basic_ostream
到std::vector<std::uint8_t>
. - 发送
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)进行建模和序列化的解决方案。
到目前为止,我已经研究了以下方法:
代码:
// 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/