3

各エントリに長さと値が含まれる 2 次元配列があるとします。

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

各フィールドを適切な長さにするために、先頭にゼロを付けてメモリに順番に格納したいと考えています。上記の例は次のようになります。

    00011 000111 0 00001111

最初のブロックは 5 ビット長で、10 進数の 3 を格納します。2 番目のブロックは 6 ビット長で、10 進数の 7 を格納します。3 番目のブロックは 1 ビット長で 10 進数の 0 を格納し、最後のブロックは 8 ビット長で 10 進数の 15 を格納します。

私はいくつかのビット単位の操作でそれを行うことができますが、もっと簡単な方法があるかどうかを確認したいと思いました.

Tensilica 32 ビット RISC プロセッサ用に C でコーディングしています。

目的は、一連の Exponential-Golomb コードを記述することです。

編集:解決策:

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: /図書館)

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

ビットフィールドのようなものですか?

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 に答える