C ++解析比特流

时间:2014-04-16 20:31:54

标签: c++ boost boost-spirit

我有一个由压缩二进制组成的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?

我知道我可以通过bithift和combine来恢复int4,但是会有很多不同的消息结构比这个例子长很多。所以,如果我可以避免,我不想手动编码等等。

编辑 - 不必使用Boost,这只是我尝试尝试的尝试。

还会有很多这样的消息。但是它们会更长,最多300位。

1 个答案:

答案 0 :(得分:1)

在极少数情况下,不使用自动属性支持。

相反,我会创建一个转换函数并从语义操作中调用它。

#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的属性转换特征。