2017-02-17 9 views
1

各ワードが15ビットからなるプロジェクトのメモリ構造体を作成する必要があります。配列のサイズを調べると、サイズが2000バイトであることがわかります。コンパイラのバイト配列のためです。C言語で15bit構造体

サイズが1875バイトになるように構造体を作成する方法はありますか?

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#pragma pack(push,1) 
struct myword 
{ 
    unsigned int val : 15; 
}; 
struct mymemmory{ 

    struct myword arr[1000]; 
}; 
#pragma pack(pop) 


int main() 
{ 
    int size = sizeof(struct mymemmory); 
    printf("Size of arr: %d\n",size); 
    return 0; 
} 

私は#pragma pack(push,0)を使用する場合、私はサイズが4000バイトであることを得る:

これは私が使用したコードです。

+4

バイト境界以外のものにパックしたい場合は、シフトとマスキングを行うコードを記述する必要があると思われます。 – stark

+1

Cの構造体またはその他のオブジェクトは、アドレス可能でなければならないため、バイトアドレスの途中で開始できません。その1ビットが本当に必要な場合は、15 uint16_t要素を持つ構造体のように別の方法でパックしてください –

+0

バイト配列を使用してサイズ1875を使用し、15ビットのチャンクに手動でシフトして解析する必要があります。 – user3853544

答えて

1

15ビットのcharのマシンを持っていない場合は、15ビット値をシフトとビットマスクを使用して3つまでunsigned charに広げるために、多くのビット操作を行う必要があります。

CHAR_BITが8以上15以下のマシンでは、次のコードが動作します。

set15_le(mem, index, val)エミュレートアレイ15ビットワードのためのストレージを提供unsigned charのアレイにmemポインティングを有し、indexは15ビット・ワードのインデックスであり、そしてvalを格納する15ビットの値です。 get15_le(mem, index)は、指定されたインデックスから15ビットワードを返します。 15ビットのワードは、「リトルエンディアン」バイトオーダーで格納されます。

set15_be(mem, index, val)およびget15_be(mem, index)は、15ビットワードが「ビッグエンディアン」バイトオーダーで格納される点を除き、上記と同様です。

mainファンクションは、15ビットの擬似乱数のセットを配列に格納し、それらを読み戻し、期待値と一致するかどうかをチェックすることで、両方のフレーバをテストします。

#include <limits.h> 

#if CHAR_BIT > 15 
#error "Unsupported CHAR_BIT value" 
#endif 

unsigned short get15_le(const unsigned char *mem, unsigned long index) 
{ 
    unsigned long mem_index; 
    unsigned int mem_bitpos; 
    unsigned int val_bitpos; 
    unsigned short val_mask; 
    unsigned short val; 

    mem_index = (index * 15)/CHAR_BIT; 
    mem_bitpos = (index * 15) % CHAR_BIT; 
    val = 0; 
    val_bitpos = 0; 
    val_mask = (1U << 15) - 1; 
    while (val_mask) 
    { 
     unsigned int nbits; 
     unsigned char mem_mask; 
     unsigned char mem_byte; 

     nbits = CHAR_BIT - mem_bitpos; 
     if (nbits > 15 - val_bitpos) 
     { 
      nbits = 15 - val_bitpos; 
     } 
     mem_mask = val_mask << mem_bitpos; 
     mem_byte = mem[mem_index]; 
     mem_byte &= mem_mask; 
     val |= (mem_byte >> mem_bitpos) << val_bitpos; 
     mem_bitpos += nbits; 
     if (mem_bitpos == CHAR_BIT) 
     { 
      mem_bitpos = 0; 
      mem_index++; 
     } 
     val_bitpos += nbits; 
     val_mask >>= nbits; 
    } 
    return val; 
} 

void set15_le(unsigned char *mem, unsigned long index, unsigned short val) 
{ 
    unsigned long mem_index; 
    unsigned int mem_bitpos; 
    unsigned int val_bitpos; 
    unsigned short val_mask; 

    mem_index = (index * 15)/CHAR_BIT; 
    mem_bitpos = (index * 15) % CHAR_BIT; 
    val_bitpos = 0; 
    val_mask = (1U << 15) - 1; 
    val &= val_mask; 
    while (val_mask) 
    { 
     unsigned int nbits; 
     unsigned char mem_mask; 
     unsigned char mem_byte; 

     nbits = CHAR_BIT - mem_bitpos; 
     if (nbits > 15 - val_bitpos) 
     { 
      nbits = 15 - val_bitpos; 
     } 
     mem_mask = val_mask << mem_bitpos; 
     mem_byte = mem[mem_index]; 
     mem_byte &= ~mem_mask; 
     mem_byte |= ((val >> val_bitpos) << mem_bitpos) & mem_mask; 
     mem[mem_index] = mem_byte; 
     mem_bitpos += nbits; 
     if (mem_bitpos == CHAR_BIT) 
     { 
      mem_bitpos = 0; 
      mem_index++; 
     } 
     val_bitpos += nbits; 
     val_mask >>= nbits; 
    } 
} 

unsigned short get15_be(const unsigned char *mem, unsigned long index) 
{ 
    unsigned long mem_index; 
    unsigned int mem_bitpos; 
    unsigned int val_bitpos; 
    unsigned short val_mask; 
    unsigned short val; 

    mem_index = (index * 15)/CHAR_BIT; 
    mem_bitpos = CHAR_BIT - (index * 15) % CHAR_BIT; 
    val = 0; 
    val_bitpos = 15; 
    val_mask = (1U << 15) - 1; 
    while (val_mask) 
    { 
     unsigned int nbits; 
     unsigned char mem_mask; 
     unsigned char mem_byte; 

     nbits = mem_bitpos; 
     if (nbits > val_bitpos) 
     { 
      nbits = val_bitpos; 
     } 
     val_bitpos -= nbits; 
     mem_bitpos -= nbits; 
     mem_mask = (val_mask >> val_bitpos) << mem_bitpos; 
     mem_byte = mem[mem_index]; 
     mem_byte &= mem_mask; 
     val |= (mem_byte >> mem_bitpos) << val_bitpos; 
     if (mem_bitpos == 0) 
     { 
      mem_bitpos = CHAR_BIT; 
      mem_index++; 
     } 
     val_mask >>= nbits; 
    } 
    return val; 
} 

void set15_be(unsigned char *mem, unsigned long index, unsigned short val) 
{ 
    unsigned long mem_index; 
    unsigned int mem_bitpos; 
    unsigned int val_bitpos; 
    unsigned short val_mask; 

    mem_index = (index * 15)/CHAR_BIT; 
    mem_bitpos = CHAR_BIT - (index * 15) % CHAR_BIT; 
    val_bitpos = 15; 
    val_mask = (1U << 15) - 1; 
    val &= val_mask; 
    while (val_mask) 
    { 
     unsigned int nbits; 
     unsigned char mem_mask; 
     unsigned char mem_byte; 

     nbits = mem_bitpos; 
     if (nbits > val_bitpos) 
     { 
      nbits = val_bitpos; 
     } 
     val_bitpos -= nbits; 
     mem_bitpos -= nbits; 
     mem_mask = (val_mask >> val_bitpos) << mem_bitpos; 
     mem_byte = mem[mem_index]; 
     mem_byte &= ~mem_mask; 
     mem_byte |= ((val >> val_bitpos) << mem_bitpos) & mem_mask; 
     mem[mem_index] = mem_byte; 
     if (mem_bitpos == 0) 
     { 
      mem_bitpos = CHAR_BIT; 
      mem_index++; 
     } 
     val_mask >>= nbits; 
    } 
} 

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

struct mymemory 
{ 
    unsigned char content[(1000 * 15 + CHAR_BIT - 1)/CHAR_BIT]; 
}; 

int main(void) 
{ 
    struct mymemory mem; 
    unsigned long i; 
    unsigned short v; 

    printf("Memory size for 1000 15-bit words = %lu bytes (%lu bits)\n", 
      (unsigned long)sizeof(mem.content), 
      (unsigned long)sizeof(mem.content) * CHAR_BIT); 
    printf("Testing little-endian version\n"); 
    memset(mem.content, 42, sizeof(mem.content)); 
    srand(5); 
    for (i = 0; i < 1000; i++) 
    { 
     v = rand() & ((1U << 15) - 1); 
     set15_le(mem.content, i, v); 
    } 
    srand(5); 
    for (i = 0; i < 1000; i++) 
    { 
     unsigned int w; 

     v = rand() & ((1U << 15) - 1); 
     if ((w = get15_le(mem.content, i)) != v) 
     { 
      printf("Error at word %lu! got %u, expected %u\n", i, w, v); 
      break; 
     } 
    } 
    if (i == 1000) 
    { 
     printf("Passed!\n"); 
    } 
    printf("Testing big-endian version\n"); 
    memset(mem.content, 42, sizeof(mem.content)); 
    srand(23); 
    for (i = 0; i < 1000; i++) 
    { 
     v = rand() & ((1U << 15) - 1); 
     set15_be(mem.content, i, v); 
    } 
    srand(23); 
    for (i = 0; i < 1000; i++) 
    { 
     unsigned int w; 

     v = rand() & ((1U << 15) - 1); 
     if ((w = get15_be(mem.content, i)) != v) 
     { 
      printf("Error at word %lu! got %u, expected %u\n", i, w, v); 
      break; 
     } 
    } 
    if (i == 1000) 
    { 
     printf("Passed!\n"); 
    } 
    return 0; 
} 
+0

ビットのパッキングを 'set15_be'と' get15_be'の文字列に修正しました。その結果、15ビット値が左から右の2進数で書かれ、連続する値が左から右の順番で現れるようになりましたビットストリームは、左から右の順序で文字シーケンスに分割できます。 –

2

いいえ、ありません。ビットレベルの細分性が必要な場合は、1875バイトの配列を作成し、手動でインデックスとビットマスクを計算して、目的の15ビットを抽出する必要があります。この機能をアクセサー関数に組み込んだり、理想的にはC++などを使って作業を完全に抽象化するカスタムクラスを作ることができます(単純なインデックス作成ではすべての「実インデックス」とビットシフト/舞台裏でのマスク作業; std::vector<bool>はすでにシングルビットの場合と同じように動作します)。

もちろん、本当の正気は、それが125バイトを超えると愚かであることを理解しています。それぞれの値に対して1ビットを16で保存するシナリオは非常に少なく(特に価値が低いため)、価値があります。実際にコンパクトディスクからコンパクトディスクに変換する必要があります。読み書き時の拡張メモリ表現への表現、および書き込み時の変換時に変換されます。すべての読み書き時にすべてのシフトとマスキングを処理する面倒と計算上のオーバーヘッドを回避します。

+0

詳細な回答ありがとう –

関連する問題