我正在编写一个压缩数据的算法(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)
答案 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;
}
}