假设我有一个二维数组,其中每个条目包含一个长度和一个值:
int array[4][2] = { /* {length, value}, */
{5, 3},
{6, 7},
{1, 0},
{8, 15},
};
我想将它们按顺序存储到带有前导零的内存中,以使每个字段的长度合适。上面的例子是:
00011 000111 0 00001111
第一个块长5位,存储小数3.第二个块长6位,存储小数7。第三个块是一位长并存储十进制0,最后一个块是八位长并存储十进制15。
我可以通过一些按位操作来实现,但我想我会问是否有更简单的方法。
我使用C语言编写Tensilica 32位RISC处理器。
目的是编写一系列指数哥伦布码。
编辑:解决方案:
int main(int argc, char *argv[])
{
unsigned int i = 0, j = 0;
unsigned char bit = 0;
unsigned int bit_num = 0;
unsigned int field_length_bits = 0;
unsigned int field_length_bytes = 0;
unsigned int field_array_length = 0;
unsigned int field_list[NUM_FIELDS][2] = {
/*{Length, Value},*/
{4, 3},
{5, 5},
{6, 9},
{7, 11},
{8, 13},
{9, 15},
{10, 17},
};
unsigned char *seq_array;
// Find total length of field list in bits
for (i = 0; i < NUM_FIELDS; i++)
field_length_bits += field_list[i][LENGTH];
// Number of bytes needed to store FIELD parameters
for (i = 0; i < (field_length_bits + i) % 8 != 0; i++) ;
field_length_bytes = (field_length_bits + i) / 8;
// Size of array we need to allocate (multiple of 4 bytes)
for (i = 0; (field_length_bytes + i) % 4 != 0; i++) ;
field_array_length = (field_length_bytes + i);
// Allocate memory
seq_array = (unsigned char *) calloc(field_array_length, sizeof(unsigned char));
// Traverse source and set destination
for(i = 0; i < NUM_FIELDS; i++)
{
for(j = 0; j < field_list[i][LENGTH]; j++)
{
bit = 0x01 & (field_list[i][VALUE] >> (field_list[i][LENGTH] - j - 1));
if (bit)
setBit(seq_array, field_array_length, bit_num, 1);
else
setBit(seq_array, field_array_length, bit_num, 0);
bit_num++;
}
}
return 0;
}
void setBit(unsigned char *array, unsigned int array_len, unsigned int bit_num, unsigned int bit_value)
{
unsigned int byte_location = 0;
unsigned int bit_location = 0;
byte_location = bit_num / 8;
if(byte_location > array_len - 1)
{
printf("setBit(): Unauthorized memory access");
return;
}
bit_location = bit_num % 8;
if(bit_value)
array[byte_location] |= (1 << (7-bit_location));
else
array[byte_location] &= ~(1 << (7-bit_location));
return;
}
答案 0 :(得分:3)
您可以使用比特流库:
http://cpansearch.perl.org/src/KURIHARA/Imager-QRCode-0.033/src/bitstream.c
http://cpansearch.perl.org/src/KURIHARA/Imager-QRCode-0.033/src/bitstream.h
因为这个比特流库似乎是非常独立的,并且似乎不需要外部包含。
http://www.codeproject.com/Articles/32783/CBitStream-A-simple-C-class-for-reading-and-writin - C库,但使用Windows WORD,DWORD类型(你仍然可以使用typedef来使用这个库)
http://code.google.com/p/youtube-mobile-ffmpeg/source/browse/trunk/libavcodec/bitstream.c?r=8 - 包含许多其他包含使用比特流库的文件
如果你只想要指数golomb代码,那么就有开源C实现:
http://www.koders.com/c/fid8A317DF502A7D61CC96EC4DA07021850B6AD97ED.aspx?s=gcd
或者您可以使用位操作技术。
例如:
unsigned int array[4][2] = ???
unsigned int mem[100] = {};
int index=0,bit=0;
for (int i=0;i<4;i++) {
int shift = (32 - array[i][0] - bit);
if (shift>0) mem[index] &= array[i][1] << shift;
else {
mem[index] &= array[i][1] >> -shift;
mem[index+1] &= array[i][1] << (32+shift);
}
bit += array[i][1];
if (bit>=32) {
bit-=32;
index++;
}
}
声明:
代码仅在您的计算机字节顺序为小端的情况下有效,并且结果实际上在每个4字节边界内是小端,而跨越4字节边界的是大端。如果将mem从int类型转换为char,并将常量32替换为8,则将得到位数组的大端表示。
它还假设长度小于32.显然,您实际想要的代码将取决于有效输入的边界,以及您在字节排序方面的要求。
答案 1 :(得分:2)
你的意思是位字段吗?
struct myBF
{
unsigned int v1 : 5;
unsigned int v2 : 5;
unsigned int v3 : 1;
unsigned int v4 : 8;
};
struct myBF b = { 3, 7, 0, 15 };
我可能完全误解了你的要求。如果是这样,请评论。
更新:假设您要动态动态。让我们创建一个接受一对数组的函数,如示例和输出缓冲区:
/* Fill dst with bits.
* Returns one plus the number of bytes used or 0 on error.
*/
size_t bitstream(int (*arr)[2], size_t arrlen,
unsigned char * dst, size_t dstlen)
{
size_t total_bits = 0, bits_so_far = 0;
/* Check if there's enough space */
for (size_t i = 0; i != arrlen; ++i) { total_bits += arr[i][0]; }
if (dst == NULL || total_bits > CHAR_BIT * dstlen) { return 0; }
/* Set the output range to all zero */
memset(dst, 0, dstlen);
/* Populate the output range */
for (size_t i = 0; i != arrlen; ++i)
{
for (size_t bits_to_spend = arr[i][0], value = arr[i][1];
bits_to_spend != 0; /* no increment */ )
{
size_t const bit_offset = bits_so_far % CHAR_BIT;
size_t const byte_index = bits_so_far / CHAR_BIT;
size_t const cur_byte_capacity = CHAR_BIT - bit_offset;
/* Debug: Watch it work! */
printf("Need to store %zu, %zu bits to spend, capacity %zu.\n",
value, bits_to_spend, cur_byte_capacity);
dst[byte_index] |= (value << bit_offset);
if (cur_byte_capacity < bits_to_spend)
{
value >>= cur_byte_capacity;
bits_so_far += cur_byte_capacity;
bits_to_spend -= cur_byte_capacity;
}
else
{
bits_so_far += bits_to_spend;
bits_to_spend = 0;
}
}
}
return (bits_so_far + CHAR_BIT - 1) / CHAR_BIT;
}
注意:
如果数字arr[i][1]
不适合arr[i][0]
位,则仅存储模2 arr[i][0]
的残差。
为了完全正确,数组类型也应该是无符号的,否则初始化size_t value = arr[i][1]
可能是未定义的行为。
您可以修改错误处理行为。例如,您可以放弃事务性并将长度检查移动到主循环中。此外,您可以返回必需字节的数量,而不是返回0
,以便用户可以确定目标数组需要多大(如snptrintf
所做的那样)。
用法:
unsigned char dst[N];
size_t n = bitstream(array, sizeof array / sizeof *array, dst, sizeof dst);
for (size_t i = 0; i != n; ++i) { printf("0x%02X ", dst[n - i - 1]); }
对于您的示例,这将生成0x00 0xF0 0xE3
,即:
0x00 0xF0 0xE3
00000000 11110000 11100011
0000 00001111 0 000111 00011
padd 15 0 7 3
答案 2 :(得分:0)
在标准C中,除了你提到的“按位操作”以外,没有办法以任何方式访问小于char
的任何东西。我担心你运气不好,除非你遇到一个可以帮助你的图书馆。