質問
実行時に決定される大量のブール情報を保存しようとしています。最良の方法は何だろうと思っていました。
現在、次を使用してメモリを割り当てようとしています
pStatus = malloc((<number of data points>/8) + 1);
これで作業するのに十分なビットが得られると思う。次に、配列表記のポインターを使用して、各ブール値を参照できます。
pStatus[element]
残念ながら、これはあまりうまく機能していないようです。まず、整数値0
にメモリを初期化するのが困難です。これはmemset()
を使用して実行できますか?それでも、<=>にアクセスしようとしたときにクラッシュする理由に影響があるとは思わない。
また、このアプローチが使用するのに最適であると完全に確信しているわけでもありません。私が本当に欲しいのは、本質的にブール値の状態を反映する巨大なビットマスクです。何か見逃していませんか?
解決
pStatus = malloc((<number of data points>/8) + 1);
これは、ビットに十分なバイトを割り当てます。ただし、
pStatus[element]
これは、ビットではなく要素の byte にアクセスします。そのため、要素が合計ビット数の8分の1を超える場合、割り当てられた配列の最後からアクセスします。
いくつかのヘルパー関数を定義します
int get_bit(int element)
{
uint byte_index = element/8;
uint bit_index = element % 8;
uint bit_mask = ( 1 << bit_index);
return ((pStatus[byte_index] & bit_mask) != 0);
}
void set_bit (int element)
{
uint byte_index = element/8;
uint bit_index = element % 8;
uint bit_mask = ( 1 << bit_index);
pStatus[byte_index] |= bit_mask);
}
void clear_bit (int element)
{
uint byte_index = element/8;
uint bit_index = element % 8;
uint bit_mask = ( 1 << bit_index);
pStatus[byte_index] &= ~bit_mask;
}
(明確にするために省略した要素の範囲のエラーチェック。このマクロも作成できます)
他のヒント
...これで作業するのに十分なビットが得られると考えています。次に、配列表記のポインターを使用して各ブール値を参照できます:
pStatus[element]
要素はビットではなく、バイトに対応しています。次のようなものが必要です:
pStatus[element/8] & (1 << (element % 8))
小さなポイント:Nビットを格納するのに十分なメモリを取得するには、(N / 8)+ 1バイトは不正確です(1つが多すぎる可能性があります)。
ただし、(N + 7)/ 8は常に最小数です。
まあ、最も簡単な答えはmallocの代わりにcallocを使用することです。
割り当てられたメモリをゼロに初期化するように定義されており、多くの場合、ページマッピングトリックを使用して実行できます。
これにより、メモリの初期化の問題が処理されます。ここにある他の12の投稿は、インデックス作成の問題と、余分なバイトをときどき割り当てているという事実(恐ろしい!)に適切に対処しているように見えるので、ここではその内容を繰り返しません。
pStatus [element]は、そのアドレスでバイト全体を提供します。
特定の要素を設定するには、次のようにします:
pStatus[element >> 3] |= 1 << (element & 7);
要素をリセットするには:
pStatus[element >> 3] &= ~1 << (element & 7);
要素をテストするには:
if (pStatus[element >> 3] & (1 << (element & 7)) != 0)
最初の割り当ては次のようになります
pstatus = malloc((<number of data points> + 7) / 8)
あなたが持っていたものは動作しますが、時々バイトを浪費します
ここでのCのすべての応答は、1バイトが8ビットであると仮定しているように見えますが、仕方がありません。これはCでは必ずしも当てはまりません(ほとんどの主流のハードウェアではもちろん当てはまります)ので、この仮定をコードで行うのはかなり悪い形式です。
アーキテクチャに依存しないコードを記述する適切な方法は次のとおりです
#include <limits.h>
そして<!> quot; CHAR_BIT
<!> quot;のビット数;。
char
マクロを使用します。 自分自身を幸せにし、タイプとそのタイプを操作する関数を定義します。そうすれば、ビットアクセスが遅すぎることがわかった場合、ブール値ごとのメモリの単位をバイト/ワード/ロングに変更したり、メモリが本当に問題である場合(つまり、セットがほとんどゼロの場合)にスパース/動的データ構造を採用したりできます。 、1の座標のリストを保持できます。
ビットベクトルの実装の変更を完全に免除するようにコードを記述できます。
pStatus [element]はビットをアドレス指定しません。取得する正確なバイトは、pStatusのタイプに依存します-char *または同等のものを想定しています-したがって、pStatus [element]は要素のバイトを取得します。
memsetを0に設定できます、はい。
pStatus = malloc((<number of data points>/8) + 1);
その部分は問題ありません。
pStatus[element]
ここで問題が発生します。ビットをアドレスする場合、アドレスバイトです。
pStatus[element / 8 ]
配列内の正しいバイトを取得します。
c = malloc((N+7)/8)
バイトを割り当てる必要があり、n番目を設定するには
c[n/8]=((c[n/8] & ~(0x80 >> (n%8))) | (0x80>>(n%8)));
クリア
c[n/8] &= ~(0x80 >> (n%8));
およびテスト
if(c[n/8] & (0x80 >> (n%8))) blah();
ラッパーを記述する必要がない場合は、C ++のSTLのbit_setまたはbit_vectorのいずれかを使用することもできます。添えもの)。
CアプリケーションでC ++コードを使用するための簡単な方法がないのは本当に残念です(いいえ、ラッパーの作成は私にとって簡単ではなく、楽しくもなく、長期的にはより多くの作業を意味します)。
std::vector<bool>
で何が問題になりますか?
ここで1つの答えだけがCHAR_BITに言及していることに驚いています。 1バイトは多くの場合8ビットですが、常にではありません。
割り当てコードは正しいです。get_bit()
関数を参照してください。 the-size-of-bit-masks#177092 ">この回答を使用してブール値にアクセスします。
ほんの数ビットに制限されている場合、eaanon01ソリューションの代わりにビットフィールドのc組み込み機能を使用することもできます(使用できる機会はほとんどありませんが、これは1つになります)
このビットバンギングについてはお勧めできます: Herny Warrens <!> quot; Hacker Delight <!> quot;
ブール値は<!> quot; never <!> quot;です。 Cの個別の値です。そのため、構造体を使用して作業を進めることができます。
mem領域を初期化しないのは本当なので、個別に初期化する必要があります。
これは、共用体の構造体と列挙型を使用してそれを行う方法の簡単な例です
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long int DWORD;
typedef unsigned long long int DDWORD;
enum STATUS
{
status0 = 0x01,
status1 = 0x02,
status2 = 0x04,
status3 = 0x08,
status4 = 0x10,
status5 = 0x20,
status6 = 0x40,
status7 = 0x80,
status_group = status0 + status1 +status4
};
#define GET_STATUS( S ) ( ((status.DDBuf&(DDWORD)S)==(DDWORD)S) ? 1 : 0 )
#define SET_STATUS( S ) ( (status.DDBuf|= (DDWORD)S) )
#define CLR_STATUS( S ) ( (status.DDBuf&= ~(DDWORD)S) )
static union {
BYTE BBuf[8];
WORD WWBuf[4];
DWORD DWBuf[2];
DDWORD DDBuf;
}status;
int main(void)
{
// Reset status bits
status.BBuf[0] = 0;
printf( "%d \n", GET_STATUS( status0 ) );
SET_STATUS( status0 );
printf( "%d \n", GET_STATUS( status0 ) );
CLR_STATUS(status0);
printf( "%d \n", GET_STATUS( status0 ) );
SET_STATUS( status_group );
printf( "%d \n", GET_STATUS( status0 ) );
system( "pause" );
return 0;
}
これが役立つことを願っています。この例では、ステータスブール値を64個まで処理でき、簡単に拡張できます。
この例は、Char = 8ビットint = 16ビットlong int = 32ビットおよびlong long int = 64ビットに基づいています
ステータスグループのサポートも追加しました。