我有一个由压缩二进制文件组成的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的属性转换特征。

10-04 13:26