5

ねえ、プログラミング パールの本には、実際にはセット表現である int の配列で指定されたインデックスのビットを設定、クリア、およびテストするためのソース コードがあります。

コードは次のとおりです。

#include<stdio.h>
#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0x1F
#define N 10000000

int a[1+ N/BITSPERWORD];

void set(int i)
{
    a[i>>SHIFT] |= (1<<(i & MASK));
}

void clr(int i)
{
    a[i>>SHIFT] &= ~(1<<(i & MASK));
}

int test(int i)
{
    a[i>>SHIFT] & (1<<(i & MASK));
}

SHIFT と MASK が定義する理由を誰か説明してもらえますか? そして、コードでのそれらの目的は何ですか?

以前の関連する質問を読みました。

4

5 に答える 5

7

VonC は、一般的なビットマスクに関する適切な回答を投稿しました。投稿したコードに固有の情報を次に示します。

ビットを表す整数を指定すると、配列のどのメンバーがそのビットを保持しているかがわかります。つまり、ビット 0 から 31 は にa[0]、ビット 32 から 63 は にa[1]、などi>>SHIFTですi / 32。これにより、ビットのどのメンバーが存在するかaがわかります。最適化コンパイラを使用すると、これらはおそらく同等です。

明らかに、そのビットフラグのどのメンバーが存在するかがわかったaので、その整数に正しいビットを設定する必要があります。これが何をするか1 << iです。ただし、32 ビット整数の 33 番目のビットにアクセスしようとしないようにする必要があるため、シフト操作は を使用して制限され1 << (i & 0x1F)ます。ここでの魔法は 31 であるため、 31 を超える場所で0x1F表されるビットを左シフトすることはありません(そうでなければ、 の次のメンバーに移動する必要があります)。ia

于 2008-11-06T07:22:27.443 に答える
6

ここから(このスレッドを開始するための一般的な回答)

ビット マスクは、整数型内の特定のビット セットを分離できるようにする値 (変数に格納される場合があります) です。

通常、マスクでは、関心のあるビットが 1 に設定され、他のすべてのビットが 0 に設定されます。マスクを使用すると、ビットの値を分離したり、すべてのビットをクリアしたり、すべてのビットを設定したり、新しい値を設定したりできます。ビットに。

マスク (特にマルチビットのもの) には、多くの場合、関連するシフト値があります。これは、マスクされた最下位ビットが型の最下位ビットにシフトされるように、ビットを左にシフトする必要がある量です。

たとえば、16 ビットの short データ型を使用して、ビット 3、4、および 5 (LSB は番号 0) をマスクできるようにしたいとします。マスクしてシフトすると、次のようになります

#define MASK 0x0038
#define SHIFT 3

10 進数ではなく、16 進数のデータ型のビットを扱う方が簡単であるため、マスクは多くの場合 16 進数で割り当てられます。歴史的に、8 進数はビット マスクにも使用されてきました。

マスクが関連するデータを含む変数 var がある場合、このようにビットを分離できます

var & MASK

このように他のすべてのビットを分離できます

var & ~MASK

このようにビットをクリアできます

var &= ~MASK;

このように他のすべてのビットをクリアできます

var &= MASK;

このようにすべてのビットを設定できます

var |= MASK;

このように他のすべてのビットを設定できます

var |= ~MASK;

このようなビットの10進値を抽出できます

(var & MASK) >> SHIFT

このようにビットに新しい値を割り当てることができます

var &= ~MASK;
var |= (newValue << SHIFT) & MASK;
于 2008-11-06T07:15:40.123 に答える
5

配列内にビットを設定したい場合は、

  1. 正しい配列インデックスをシークし、
  2. この配列項目内に適切なビットを設定します。

1 つの配列項目にはBITSPERWORD(=32) ビットあります。これは、インデックスiを 2 つの部分に分割する必要があることを意味します。

  • 右端の 5 ビットは配列項目のインデックスとして機能し、
  • 残りのビット (左端の 28) は、配列へのインデックスとして機能します。

あなたは得る:

  • 右端の 5を破棄することにより、左端の 28i>>SHIFTビット。
  • 右端の 5 ビット以外をマスクして、右端の 5 ビットをマスクしi & MASKます。

あなたは残りを理解していると思います。

于 2008-11-06T07:25:38.717 に答える
0

コードはN配列によってビットを格納しようとしています。配列の各要素にはBITSPERWORD(32) ビットが含まれています。

したがって、 bit にアクセスしようとしている場合は、それが格納されている配列要素のインデックス ( )iを計算する必要があります。i/32i>>SHIFT

そして、取得したばかりの配列要素のそのビットにアクセスする必要があります。

(i & MASK)配列要素(ワード)のビット位置を与える. (1<<(i & MASK))その位置のビットをセットします。

a[i>>SHIFT]これで、そのビットをで設定/クリア/テストできます(1<<i & MASK))

iは 32 ビットの数値で、ビット 6 ~ 31 はそれを格納する配列要素のインデックスであり、ビット 0 ~ 5 は単語内のビット位置を表すと考えることもできます。

于 2008-11-06T07:50:59.490 に答える
0

ビット演算Maskの先頭の段落は簡潔な説明であり、さらに研究するためのいくつかの指針が含まれています。

8 ビット バイトは、8 メンバーの宇宙からの要素のセットと考えてください。対応するビットが設定されている場合、メンバはセット内にあります。少し多く設定しても、セットのメンバーシップは変更されません(ビットは 2 つの状態しか持てません)。Cビット演算子は、マスキングシフトによってビットへのアクセスを提供します。

于 2008-11-06T07:29:09.427 に答える