将13位数组合并为unsigned char数组

时间:2014-12-12 14:56:42

标签: c arrays bit-fields bitmask array-merge

我正在编写一个压缩数据的算法(LZSS),它要求我有两个13位值,以后我必须将它们合并在一起。

但在某些情况下,我不需要13位; 8就够了。 为此,我有一个这样的结构:

typedef struct pattern
{
    char is_compressed:1; //flag
    short index :13; //first value
    short length :13;  //second value
    unsigned char c;   //is 8 bits are enough, use this instead
} Pattern;

因此我有一个这样的结构数组,每个结构可以包含两个13位值或一个8位值。

我现在循环遍历这个数组,我的目标是将所有这些位合并在一起。

我很容易计算出使用的总位数和unsigned char s(8位)数组的数量,以便存储所有值:

int compressed = 0, plain = 0;
  //count is the amount of patterns i have and p is the array of patterns (the structures)
for (int i = 0; i < count; i++)
{
    if (p[i]->is_compressed)
        compressed++;
    else
        plain++;
}
  //this stores the number of bits used in the pattern (13 for length and 13 for the index or 8 for the plain uchar)
int tot_bits = compressed * 26 + plain * 8;
  //since we can only write a minimum of 8 bits, we calculate how many arrays are needed to store the bits
int nr_of_arrays = (tot_bits % 8 == 0) ? tot_bits / 8 : (tot_bits / 8) + 1;
  //we allocate the needed memory for the array of unsigned chars that will contain, concatenated, all the bits
unsigned char* uc = (unsigned char*) malloc(nr_of_arrays * sizeof(unsigned char));

在为阵列I分配内存后,我只需循环遍历结构数组,并识别我看到的结构是否包含两个13位值或仅仅是8 - 一个

for (int i = 0; i < count; i++)
{
    if (p->is_compressed)
    {
        //The structure contains the two 13 bits value
    } 
    else
    {
        //The structure only contains the 8 bits value
    }
}

我在这里陷入困境,似乎无法找到完成工作的正确方法。

你们中的任何人都知道如何在那里实施那部分吗?


一个实际的例子是:

模式1包含2个13位值:

1111 1111 1111 1
0000 0000 0000 0

模式2包含8位值

1010 1010

总比特:34
所需的阵列数量:5(将浪费6位)

结果数组是:

[0] 1111 1111
[1] 1111 1000
[2] 0000 0000
[3] 0010 1010
[4] 1000 0000 (the remaining 6 bits are set to 0)

2 个答案:

答案 0 :(得分:1)

一种方法是逐个写入字节,并在写入时跟踪部分字节。

您需要一个指向char数组的指针,以及一个整数来跟踪您写入最后一个字节的位数。每次写入位时,都会检查可写入最后一个字节的位数,并相应地写入这些位(例如:如果有5位可用,则将下一个值移位3并将其添加到最后一个字节) 。每次完成一个字节时,都会递增数组指针并重置位跟踪器。

实现这一目标的一种简洁方法是编写如下函数:

void BitWriter_init( char *myArray );
void BitWriter_write( int theBitsToWrite, int howManyBits );

现在您只需要弄清楚如何实现这些功能,或者使用您选择的任何其他方法。

答案 1 :(得分:0)

这个问题引起了我的兴趣。这是“通过使用大量按位运算”的可能实现:

/* A writable bit string, with an indicator of the next available bit */
struct bitbuffer {
    uint8_t *bytes;
    size_t next_bit;
};

/*
 * writes the bits represented by the given pattern to the next available
 * positions in the specified bit buffer
 */
void write_bits(struct bitbuffer *buffer, Pattern *pattern) {
    /* The index of the byte containing the next available bit */
    size_t next_byte = buffer->next_bit / 8;
    /* the number of bits already used in the next available byte */
    unsigned bits_used = buffer->next_bit % 8;

    if (pattern->is_compressed) {
        /* assemble the bits to write in a 32-bit block */
        uint32_t bits = pattern->index << 13 + pattern->length;

        if (bits_used == 7) {
            /* special case: the bits to write will span 5 bytes */

            /* the first bit written will be the last in the current byte */
            uint8_t first_bit = bits >> 25;

            buffer->bytes[next_byte] |= first_bit;

            /* write the next 8 bits to the next byte */
            buffer->bytes[++next_byte] = (bits >> 17) & 0xFF;

            /* align the tail of the bit block with the buffer*/
            bits <<= 7;
        } else {

            /* the first bits written will fill out the current byte */
            uint8_t first_bits = (bits >> (18 + bits_used)) & 0xFF;

            buffer->bytes[next_byte] |= first_bits;

            /* align the tail of the bit block with the buffer*/
            bits <<= (6 - bits_used);
        }

        /*
         * Write the remainder of the bit block to the buffer,
         * most-significant bits first. Three (more) bytes will be modified.
         */
        buffer->bytes[++next_byte] = (bits >> 16) & 0xFF;
        buffer->bytes[++next_byte] = (bits >>  8) & 0xFF;
        buffer->bytes[++next_byte] =  bits        & 0xFF;

        /* update the buffer's index of the next available bit */
        buffer->next_bit += 26;
    } else {  /* the pattern is not compressed */
        if (bits_used) {
            /* the bits to write will span two bytes in the buffer */
            buffer->bytes[next_byte] |= (pattern->c >> bits_used);
            buffer[++next_byte] = (pattern->c << bits_used) & 0xFF;
        } else {
            /* the bits to write exactly fill the next buffer byte */
            buffer->bytes[next_byte] = pattern->c;
        }

        /* update the buffer's index of the next available bit */
        buffer->next_bit += 8;
    }
}