【问题标题】:Copying arbitrary bits from an array into a variable?将数组中的任意位复制到变量中?
【发布时间】:2020-01-02 03:06:43
【问题描述】:

所以我正在处理一个以数组形式出现的数据集。例如:

{0x00, 0x00, 0xFF, 0xF1, 0x6D, 0xA2, 0x00 0x00}

{0b00000000, 0b00000000, 0b11111111, 0b11110001, 0b01101101, 0b10100010, 0b00000000, 0b00000000}

我需要能够根据两个值从这个数组中提取信息:

  • 起始位。
  • 位数。

例如,如果起始位是 17,位长是 13,(假设第一位是索引 0),我的数据将是:

0b1111111111100

十进制:8188

然后,这个十进制值(或 uint32_t 或 w/e)将存储在一个变量中并输出。我可以针对单个案例执行此操作,但是很难将起始位和位数作为函数或代码块的变量的代码编写...


我尝试过使用 memcpy,但这只是字节可寻址的。

如有任何反馈,我将不胜感激!

【问题讨论】:

  • 可能是基于std::bitset 的东西? boost::dynamic_bitset 也可能是可行的。
  • 首先创建一个返回单个位的函数。然后在循环中调用它并逐个获取所需的位。一旦成功,如果您需要更高的性能,您应该更好地了解如何以更大的块而不是一个接一个地获取位。
  • & 用于按位与,<< 用于for 循环内的位移?我想我古老的旧 C 正在展示而不是花哨的新 C++...
  • 我不明白“如果起始位是 17”。请显示您提到的单个案例的代码。

标签: c++ arrays bit memcpy


【解决方案1】:

@Punchki 如果你想自己建造一台机器,也许这个想法会有所帮助。

                 First (17)   Last (inclusive)
                   !            !
                   !            ! +- The least significant bit in the least significant byte
                   !            ! !
00000000 00000000 11111111 11110001 01101101 10100010 00000000 00000000
                      &        &     <- AND
                  01111111 11111100  <- 13 bit bit-mask
                                     <- cast all bytes to std::uintmax_t and ...
<<(24-2) <<(16-2)  <<(8-2)  >>(0+2)  <- ... shift and ...
                 |                   <- ... OR all into the result variable
                  00011111 11111100

【讨论】:

    【解决方案2】:

    从所需的起始位索引,您可以使用/% 运算符计算数组中的确切字节,以及该字节内的初始位索引。然后只需迭代字节数组并移动位,直到将所需的位数复制到结果中。

    例如:

    uint32_t getBits(const void *Data, uint32_t DataLen, uint32_t StartBit, uint8_t NumBits)
    {
        uint32_t Result = 0;
    
        // are there any bytes at all?
        if (DataLen != 0)
        {
            // get a pointer to the starting byte...
            const uint8_t *pData = &(static_cast<const uint8_t*>(Data)[StartBit / 8]);
            uint8_t b = *pData;
    
            // calculate the starting bit within that byte...
            int BitOffset = 7 - (StartBit % 8);
    
            // iterate for the desired number of bits...
            for(int i = 0; i < NumBits; ++i)
            {
                // make room for the next bit...
                Result <<= 1;
                // copy the bit...
                Result |= ((b >> BitOffset) & 0x01);
                // reached the end of the current byte?
                if (--BitOffset < 0)
                {
                    b = *(++pData); // go to the next byte...
                    BitOffset = 7; // restart at the first bit in that byte...
                }
            }
        }
    
        // all done...
        return Result;
    }
    
    uint8_t arr[] = {0x00, 0x00, 0xFF, 0xF1, 0x6D, 0xA2, 0x00, 0x00};
    uint32_t value = getBits(arr, 8, 17, 13);
    

    Live Demo

    如果需要,您可以进一步优化它,使代码一次移位+复制超过 1 位。例如,在进入循环之前,如果起始位索引不在字节边界处,则将不需要的位从初始的bOR 转移到剩余的位Result。然后将循环 OR 一次 1 个完整字节放入 Result,而所需的位数为 &gt;= 8。然后在退出循环后,如果所需的位数仍然是&gt; 0,则将不需要的位从最后的bOR 剩余的位移到Result

    我把它作为一个练习留给你弄清楚。

    【讨论】:

      猜你喜欢
      • 2021-06-14
      • 1970-01-01
      • 2018-09-12
      • 1970-01-01
      • 2018-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多