我有一个由压缩二进制文件组成的6字节数组。
前6位代表'int1'
以下10位代表'int2'
以下14位代表'int3'
以下16位代表'int4'
以下2位是备用的
我曾尝试使用Boost::Spirit解析为结构
struct header_t
{
union{
uint16_t firstPart;
struct{
uint16_t int1 : 6;
uint16_t int2 : 10;
};
};
union{
uint16_t secondPart;
struct{
uint16_t int3 : 14;
uint16_t int4_lo : 2;
};
};
union{
uint16_t thirdPart;
struct{
uint16_t int4_hi : 14;
uint16_t spare : 2;
};
};
};
BOOST_FUSION_ADAPT_STRUCT(
header_t,
(uint16_t, firstPart)
(uint16_t, secondPart)
(uint16_t, thirdPart))
typedef const char* parse_iter_t;
int main()
{
using qi::big_word;
parse_iter_t iter = "\xff\x3e"
"\x44\x77"
"\x35\x19";
parse_iter_t iter_end = iter + std::strlen(iter);
qi::rule< parse_iter_t, header_t() > header_rule;
header_rule = big_word >> big_word >> big_word;
header_t result;
BOOST_TEST(qi::parse( iter, iter_end, header_rule, result ));
}
这类作品。
int1 = a = 62(符合预期)
int2 = b = 1020(符合预期)
int3 = c = 1143(符合预期)
int4这就是它掉落的地方。如您所见,该值在int4_lo和int4_hi之间分配。
我该如何改善它,以便在解析过程中总共恢复int4?
我知道我可以移位并合并以恢复int4,但是将有许多不同的消息结构,它们比本示例更长。因此,如果可以避免的话,我不想手动编码移位等。
编辑-不必使用Boost,这只是我的尝试。
还将有数十条这样的消息。但是它们会更长,最多300位。
最佳答案
在这种罕见的情况下,不使用自动属性支持。
相反,我将创建一个转换函数并从语义 Action 中调用它。
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
struct header_t
{
header_t(uint16_t i1=0, uint16_t i2=0, uint16_t i3=0, uint16_t i4=0) : int1(i1), int2(i2), int3(i3), int4(i4) { }
static header_t make(uint16_t w1, uint16_t w2, uint16_t w3)
{
#define BITS(n) ((1ul << (n)) - 1u)
return header_t(
(w1 & BITS(6u)), // 6
(w1 >> 6u), // 10
(w2 & BITS(14u)), // 14
// 2+14
(((w3 & BITS(14)) << 2) | (w2 >> 14u) ));
}
uint16_t int1; // 6
uint16_t int2; // 10
uint16_t int3; // 14
uint16_t int4; // 2+14
};
typedef const char* parse_iter_t;
int main()
{
using qi::big_word;
parse_iter_t iter = "\xff\x3e"
"\x44\x77"
"\x35\x19";
//parse_iter_t iter = "\xff\xff"
//"\xff\xff"
//"\xff\xff";
parse_iter_t iter_end = iter + std::strlen(iter);
qi::rule<parse_iter_t, header_t()> header_rule;
header_rule = (big_word >> big_word >> big_word)
[ qi::_val = boost::phoenix::bind(header_t::make, qi::_1, qi::_2, qi::_3) ];
header_t result;
bool ok = qi::parse(iter, iter_end, header_rule, result);
if (ok)
{
std::cout << "int1: " << std::dec << result.int1 << " " << std::hex << std::showbase << result.int1 << "\n";
std::cout << "int2: " << std::dec << result.int2 << " " << std::hex << std::showbase << result.int2 << "\n";
std::cout << "int3: " << std::dec << result.int3 << " " << std::hex << std::showbase << result.int3 << "\n";
std::cout << "int4: " << std::dec << result.int4 << " " << std::hex << std::showbase << result.int4 << "\n";
}
assert(ok);
}
打印品:
int1: 62 0x3e
int2: 1020 0x3fc
int3: 1143 0x477
int4: 54373 0xd465
看到它 Live on Coliru
另外,您可以专门指定
header_t
的属性转换特征。