【问题标题】:Parsing long strings of binary data with C++用 C++ 解析长的二进制数据字符串
【发布时间】:2020-11-01 16:34:50
【问题描述】:

我正在寻找如何解析长二进制数据的想法,例如:“10100011111000111001” 位:0-4 是 id 位 5-15 是数据 等等等等……

二进制数据结构可以改变,所以我需要建立一个数据库来存储数据如何解析每个字符串。

插图(可能是 200~ 位):

想法如何实现? 谢谢

编辑

我在这里错过了什么?

struct Bitfield {
uint16_t  a : 10 , b:6;};


void diag(){
uint16_t t= 61455;
struct Bitfield test = {t};

cout<<"a: "<<test.a<<endl;
cout<<"b: "<<test.b<<endl;

return;}

输出是:

a: 15
b: 0

【问题讨论】:

  • 实现它的最佳方式是什么? -- 没有“最佳方式”,因为这是非常主观的。只有“方法”。
  • 可能是std::bitset,虽然它缺少一些便利功能
  • 你真的把那个叫做长二进制序列?!!它只有 16 位。它甚至可以放入int!请告诉我们更多关于您希望对该数据施加的约束,包括序列的最大长度。
  • 数据从何而来?它存储在字节数组中还是作为字节iostream?位是如何编号的?位如何从一个字节跨越到另一个字节?您必须对问题给出更准确的说明。
  • 它只是一串“1”和“0”,它不是字节数据,只是比特流

标签: c++ parsing binary bit-manipulation


【解决方案1】:

可用选项

要管理大量结构化的位,您有以下选择:

  • C++ bit-fields:你定义了一个包含位域成员的结构。您可以拥有任意数量的成员,前提是每个成员的位数不超过 unsigned long long
    它超级容易使用;编译器为您管理对位或位组的访问。主要的不便之处在于位布局取决于实现。因此,这不是编写以二进制格式交换数据的可移植代码的选择。

  • 无符号整数类型的容器:您定义一个足够大的数组来保存所有位,并使用逻辑操作的组合访问位或位组。 它需要轻松进行二进制操作,如果位组被拆分为连续的元素,则不实用。为了以可移植的方式与外部世界交换二进制格式的数据,您需要注意大小端架构之间的差异,或者使用uint8_t 的数组。

  • std::vector&lt;bool&gt;:为您提供管理位的完全灵活性。主要限制是您需要分别处理每个位。此外,没有data() 成员可以直接访问二进制数据。

  • std::bitset:与vector&lt;bool&gt; 非常相似,用于访问位。它在编译时具有固定大小,但提供了有用的功能,例如从字符串或流以 ascci 格式读取和写入二进制文件]5、从整数类型的二进制值转换以及对完整位集的逻辑运算。

  • 这些技术的组合

做出选择

要以便携的方式与外界通信,最简单的方法是使用位集。位集提供了使用 ascci '0' 或 '1'(或任何替代品)的格式的简单输入/输出/字符串转换

bitset<msg_header_size> bh,bh2;
bitset<msg_body_size> bb,bb2;
cin>>bh>>bb;  // reads a string od ascii 0 and 1 
cout<<bh<<"-"<<bb<<endl<<endl;  // writes a string of ascii 0 and 1

您还可以从/转换为二进制数据(但单个元素,对于 bitset 大小足够大):

bitset<8> b(static_cast<uint8_t>(c));
cout<<b<<endl; 
cout<<b.to_ulong()<<endl;  

要读取/写入大型集,您需要读取小型位集并使用逻辑运算符将它们聚合到更大的位集中。这看起来很耗时,实际上非常接近您在积分容器中所做的事情,但不必关心字节边界。

在您的情况下,使用固定大小的标头和最大大小,bitset 似乎是与外部世界交换二进制数据的不错选择(但要小心,因为变量部分是右对齐的)。

为了处理数据内容,访问特定位很容易,但您必须使用一些逻辑运算(移位和与)来访问位组。此外,如果你想要可读和可维护的代码,最好将位布局抽象出来。

结论:

因此,我强烈建议在内部使用位域结构来处理数据,并同时保持与原始数据相当的内存占用,使用位集只是为了外部数据交换目的从/到这个结构转换。

【讨论】:

  • 首先谢谢大家,我的数据流可能包含~200位,但每组位有不同的含义。所以我认为我的主要问题是如何存储该数据库如何解析这个长班次以及如何在解析后存储数据。
  • @Elior 也许结合方法和对于每个组 m,而不是位域,使用位集?
  • @Elior 1) 数据是否为二进制格式? 2)您必须以二进制格式导出数据吗? 3)数据的大小是固定的(200位)还是有34位是固定的和可变的部分?
  • @Elior 好的。关于 1:当您说“字符串”时,您是指由“0”和“1”组成的可打印 ascii 字符串,还是指未经转换打印会导致垃圾的二进制字节字符串?大约3:有最大长度吗?
  • @Elior 好的,我想我明白了。我已经编辑了答案以解释选择,并添加了一个关于如何根据您的要求进行选择的部分。结论为您提供了满足您需求的最合适的方法。
【解决方案2】:

“最好的方法”取决于问题的细节。

如果整数适合可用的最大整数类型(通常是 long long),请先将字符串转换为整数(例如,使用 stoi/stol/stoll 函数,假设 C++11 可用)。然后使用位移结合二进制和 (&) 来提取您感兴趣的值的部分。

如果整数不适合可用的最大整数类型,请将其分割为字符串(使用 substr 函数),然后将子字符串一一转换为整数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-04
    • 2011-11-18
    • 1970-01-01
    • 2011-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-23
    相关资源
    最近更新 更多