3

假设我有一个二维数组,其中每个条目包含一个长度和一个值:

int array[4][2] =  { /* {length, value}, */
                   {5, 3},
                   {6, 7},
                   {1, 0},
                   {8, 15},
                   };

我想用前导零将它们按顺序存储到内存中,以使每个字段都具有适当的长度。上面的例子是:

    00011 000111 0 00001111

第一个块长 5 位,存储十进制 3。第二个块长 6 位,存储十进制 7。第三个块长 1 位,存储十进制 0,最后一个块长 8 位,存储十进制 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;
}
4

3 回答 3

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 - 包括许多其他包含文件以使用比特流库


如果你只想要指数哥伦布代码,有开源 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。显然,您实际想要的代码将取决于有效输入的范围,以及您想要的字节顺序。

于 2012-08-17T23:49:35.043 回答
2

你的意思是像bit field吗?

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
于 2012-08-17T23:37:52.333 回答
0

char在标准 C 中,除了您提到的“按位操作”之外,没有其他方法可以访问小于 a的任何内容。恐怕你运气不好,除非你在某个地方遇到可以帮助你的图书馆。

于 2012-08-17T23:36:11.453 回答