Cでのビットごとのインデックス作成?
-
09-06-2019 - |
質問
私は自分が持っていたデータ圧縮のアイデアを実装しようとしていますが、大規模なテスト データのコーパスに対してそれを実行することを想像しているので、それを C でコード化しようと考えていました (私は主に Ruby などのスクリプト言語の経験があります) Tcl.)
C に関する O'Reilly の「cow」本を読んでいると、ビット単位の比較や演算子を実行したいのに、単純な 'char' 型または 'int' 型の変数のビットにインデックスを付けるだけでは不可能であることがわかりました。
この認識は正しいでしょうか?ビットを表すために列挙型を使用する (そしてこれらの配列を作成し、char との間で変換する関数を記述する) ことは合理的ですか?もしそうなら、そのような型や関数は標準ライブラリのどこかにすでに定義されているのでしょうか?他の(より良い)アプローチはありますか?どこかに誰かが教えてくれるサンプルコードはありますか?
ありがとう -
解決
カイルの言ったことに従うと、マクロを使用して難しい作業を行うことができます。
可能です。
n 番目のビットを設定するには、OR を使用します。
x |= (1 << 5);// 6番目の右を設定します
ビットをクリアするには、AND を使用します。
x &= ~(1 << 5);//右から6番目にクリアします
ビットを反転するには、XOR を使用します。
x ^= (1 << 5);// 右から 6 番目を反転します
または...
#define GetBit(var, bit) ((var & (1 << bit)) != 0) // Returns true / false if bit is set
#define SetBit(var, bit) (var |= (1 << bit))
#define FlipBit(var, bit) (var ^= (1 << bit))
その後、次のようなコードで使用できます。
int myVar = 0;
SetBit(myVar, 5);
if (GetBit(myVar, 5))
{
// Do something
}
他のヒント
可能です。
n 番目のビットを設定するには、OR を使用します。
x |= (1 << 5); // sets the 5th-from right
ビットをクリアするには、AND を使用します。
x &= ~(1 << 5); // clears 5th-from-right
ビットを反転するには、XOR を使用します。
x ^= (1 << 5); // flips 5th-from-right
ビットの値を取得するには、シフトと AND を使用します。
(x & (1 << 5)) >> 5 // gets the value (0 or 1) of the 5th-from-right
注記:右シフト 5 は、値が 0 または 1 になるようにするためのものです。0 ではない 0 だけに興味がある場合は、シフトなしでも問題ありません。
に対する答えを見てみましょう この質問.
理論
組み込みデータ型の n 番目のビットにアクセスしたり設定したりするための C 構文はありません (例:「文字」)。ただし、論理 AND 演算を使用してビットにアクセスし、論理 OR 演算を使用してビットを設定することができます。
例として、1101 を保持する変数があり、左から 2 番目のビットをチェックしたいとします。単純に 0100 と論理 AND を実行します。
1101
0100
---- AND
0100
結果がゼロ以外の場合は、2 番目のビットが設定されている必要があります。それ以外の場合は設定されていません。
左から 3 番目のビットを設定する場合は、0010 と論理 OR を実行します。
1101
0010
---- OR
1111
c演算子&&(for and)および||を使用できます(または)これらのタスクを実行する。ビット アクセス パターン (上記の例では 0100 と 0010) を自分で構築する必要があります。コツは、最下位ビット (LSB) が 1 をカウントし、次の LSB が 2 をカウントし、次に 4 をカウントするということを覚えておくことです。したがって、n 番目の LSB (0 から始まる) のビット アクセス パターンは、単純に 2^n の値になります。C でこれを計算する最も簡単な方法は、バイナリ値 0001 (この 4 ビットの例では) を必要な桁数だけ左にシフトすることです。この値は符号なし整数のような数量では常に 1 に等しいため、これは単に「1 << n」になります。
例
unsigned char myVal = 0x65; /* in hex; this is 01100101 in binary. */
/* Q: is the 3-rd least significant bit set (again, the LSB is the 0th bit)? */
unsigned char pattern = 1;
pattern <<= 3; /* Shift pattern left by three places.*/
if(myVal && (char)(1<<3)) {printf("Yes!\n");} /* Perform the test. */
/* Set the most significant bit. */
myVal |= (char)(1<<7);
この例はテストされていませんが、一般的なアイデアを説明するのに役立ちます。
特定のインデックスを使用してビットの状態をクエリするには、次のようにします。
int index_state = variable & ( 1 << bit_index );
ビットを設定するには:
varabile |= 1 << bit_index;
ビットを再起動するには:
variable &= ~( 1 << bit_index );
個々のビットには次のようにインデックスを付けることができます。
次のような構造体を定義します。
struct
{
unsigned bit0 : 1;
unsigned bit1 : 1;
unsigned bit2 : 1;
unsigned bit3 : 1;
unsigned reserved : 28;
} bitPattern;
ここで、「value」という名前の var の個々のビット値を知りたい場合は、次の手順を実行します。
CopyMemory( &input, &value, sizeof(value) );
ビット 2 が High か Low かを確認するには、次のようにします。
int state = bitPattern.bit2;
お役に立てれば。
ビットフィールドを使用してみてください。実装はコンパイラによって異なる場合があることに注意してください。
http://publications.gbdirect.co.uk/c_book/chapter6/bitfields.html
少しインデックスを付けたい場合は、次のようにできます。
bit = (char & 0xF0) >> 7;
charのmsbを取得します。右シフトを省略して 0 でテストすることもできます。
bit = char & 0xF0;
ビットが設定されている場合、結果は > 0 になります。
明らかに、異なるビットを取得するにはマスクを変更する必要があります (注意:不明瞭な場合、0xF はビットマスクです)。多数のマスクを定義することが可能です。
#define BIT_0 0x1 // or 1 << 0
#define BIT_1 0x2 // or 1 << 1
#define BIT_2 0x4 // or 1 << 2
#define BIT_3 0x8 // or 1 << 3
等...
これにより、次のことが得られます。
bit = char & BIT_1;
上記のコードでこれらの定義を使用すると、マクロまたは関数内のビットに正常にインデックスを付けることができます。
ビットを設定するには:
char |= BIT_2;
少しクリアするには:
char &= ~BIT_3
少し切り替えるには
char ^= BIT_4
この助け?
ビット用の標準ライブラリ コンテナがあります。std::vector。図書館に特化して省スペース化を実現。ブーストのdynamic_bitsetクラスもあります。
これらにより、基礎となるストレージの値ごとに 1 ビットを使用して、一連のブール値に対して操作を実行できるようになります。
STL ドキュメントについては、コンパイラのドキュメントを参照してください。
もちろん、他の整数型の個々のビットを手動でアドレス指定することもできます。その場合は、上位ビットが設定された値に対して右シフトを実行する場合に未定義の動作が発生しないように、符号なし型を使用する必要があります。ただし、コンテナが欲しいようです。
これには必要以上の 32 倍のスペースが必要だと主張したコメント投稿者へ:boost::dynamic_bitset と Vector はエントリごとに 1 ビットを使用するように特殊化されているため、実際にはプリミティブ型のビット数以上が必要であると仮定しても、スペースのペナルティはありません。これらのクラスを使用すると、効率的な基礎となるストレージを使用して、大きなコンテナ内の個々のビットをアドレス指定できます。(たとえば) 32 ビットだけが必要な場合は、必ず int を使用してください。大量のビットが必要な場合は、ライブラリ コンテナを使用できます。