【问题标题】:How do I parse out n-bit elements from a byte addressable array如何从字节可寻址数组中解析出 n 位元素
【发布时间】:2009-12-08 22:14:37
【问题描述】:

我有一个只能以 8 位字节寻址的数据流,我想将其解析为 6 位元素并将其存储到数组中。有没有最知名的方法可以做到这一点?

11110000 10101010 11001100 

进入

类似的数组

111100|001010|101011|001100

(可以有零填充,只需要这样寻址)

而且数据是一个 8 位数组,也是 6 位的倍数,并不是真的无穷无尽

【问题讨论】:

  • 这是一个恒定的、无穷无尽的 5 位数据元素流,还是一个已知的重复结构?
  • 也许有一些纠错冗余,总是假设最好的;-)
  • 这些字节是先写入最低有效位还是先写入最高有效位?换句话说,是 (15, 85, 51) 还是 (240, 170, 204) ?
  • 在人们开始回答您的问题后,将您的问题从“5”位更改为“6”位是一种不好的形式。

标签: c parsing bit-fields


【解决方案1】:

取决于一个字节在您的特定架构上具有多少位。在六位架构上它非常简单:-)

假设每字节 8 位架构,您将不得不按照以下方式做一些事情:

int sixbits(unsigned char* datastream, unsigned int n) {
    int bitpos = n*6;
    return (datastream[bitpos/8] >> bitpos%8)    // lower part of the five bit group
        + (datastream[bitpos/8+1] << 8-bitpos%8) // if bitpos%8>2, we need to add some carry bits from the next char
        & 0x3f;                                  // and finally mask the lowest 6 bits
}

其中 n 是第 n 个 6 位组。任何体面的编译器都会用移位代替除法,用ands代替模数。只需在循环中使用此函数即可填充您的目标数组。

【讨论】:

  • +1 不错的解决方案,比我的快得多。不过,您可能想要修复“错误:未声明的‘索引’”。
  • 谢谢,已修复。删除了一些不必要的括号,为 cmets 腾出更多位置;-) 对于非 C 语言的人,优先级应该通过额外的空格来明确。
【解决方案2】:

您计算 5 位序列,读取每个字节,根据您的计数器和预期的字位置移动位(通过对相邻字节字进行异或运算),然后形成新的正确对齐的字节字,然后进行处理。

我希望你不要期望代码...

【讨论】:

    【解决方案3】:

    您可以使用位摆弄来做到这一点:

    #include <stdio.h>
    #include <string.h>
    
    int main(int argc, char *argv[])
    {
        unsigned char source[3] = { 15, 85, 51 };
        unsigned char destination[4];
        memset(destination, 0, 4);
        for (int i = 0; i < (8 * 3); ++i)
        {
            destination[i / 6] |= ((source[i / 8] >> (i % 8) & 1) << (i % 6));
        }
    
        for (int j = 0; j < 4; ++j)
            printf("%d ", destination[j]);
    }
    

    输出:

    15 20 53 12
    

    请注意,这从五个最低位开始工作。

          15       85       51
    11110000 10101010 11001100
    111100 001010 101011 001100
        15     20     53     12
    

    要首先获得最重要的信息,请改为这样做:

    destination[i / 6] |= ((source[i / 8] >> (7 - (i % 8))) & 1) << (5 - (i % 6));
    

    这和你的例子一样,假设你先写了最重要的位:

    240      170      204
    11110000 10101010 11001100
    111100 001010 101011 001100
    60     10     43     12
    

    【讨论】:

    • 当您只使用 3 个索引时,为什么是 source[6]?另外,我会设置unsigned char destinatio[4] = {0}; 只是为了安全,但我不知道这很重要。
    • 1) 在早期版本中是 6 个。我只是忘了改变它。 2)我在下一行将目标数组设置为零。
    【解决方案4】:

    如何使用这样的结构:

    struct bit5
    {
        unsigned int v1 : 5;
        unsigned int v2 : 5;
        unsigned int v3 : 5;
        unsigned int v4 : 5;
        unsigned int v5 : 5;
        unsigned int v6 : 5;
        unsigned int v7 : 5;
        unsigned int v8 : 5;
    }; 
    

    然后每 8 个字节(40 位 = 8 组 5 位,适合 8 个字节)将字节数组转换为 struct bit5 以获得 5 位块。说:

    unsigned char* array; // a byte array that you want to convert
    int i;
    struct bit5* pBit5;
    
    for(i = 0; i < (int)(SIZE_OF_ARRAY / 8); i++)
        pBit5 = (struct bit5*)((int)array + i * 8);
    

    【讨论】:

      【解决方案5】:

      我会考虑使用 BitStream。它将允许您一次读取一位。您可以将该位直接移动到位(使用

      【讨论】:

        【解决方案6】:

        这个联盟怎么样?

        union _EIGHT_TO_SIX_ {
        
            struct {
        
               unsigned char by6Bit0 : 6;
               unsigned char by6Bit1 : 6;
               unsigned char by6Bit2 : 6;
               unsigned char by6Bit3 : 6;
        
            } x6;
        
            struct {
        
               unsigned char by8Bit0;
               unsigned char by8Bit0;
               unsigned char by8Bit0;
        
            } x8;
        }
        

        设置by8Bitx会自动填写by6Bitx~~~

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-02
          • 1970-01-01
          • 2011-02-13
          • 1970-01-01
          • 2019-11-05
          • 1970-01-01
          相关资源
          最近更新 更多