web-dev-qa-db-ja.com

Cで最下位ビットを1に設定してマスクを作成する方法

誰かがこの機能を私に説明してもらえますか?

最下位nビットが1に設定されたマスク。

例:

n = 6-> 0x2F、n = 17-> 0x1FFFF //これらはまったく取得されません、特にn = 6-> 0x2F

また、マスクとは何ですか?

12
sebi

通常の方法は、1を取得し、それをnビット左にシフトすることです。それはあなたに次のようなものを与えるでしょう:00100000。次に、そこから1を引くと、設定されているビットがクリアされ、重要度の低いビットがすべて設定されるため、この場合は00011111になります。

マスクは通常、ビット演算、特にandで使用されます。上記のマスクを使用して、存在する可能性のある他のビットから分離された、最下位5ビットを単独で取得します。これは、完全に別個の無関係な数量やフラグの数を表すビットを含む単一のハードウェアレジスタを持つことが多いハードウェアを扱う場合に特に一般的です。

24
Jerry Coffin

正確性とパフォーマンスの両方について、これを達成するための最良の方法は、この質問が2012年に質問されて以来、最新のx86プロセッサ(特にBLSMSK)でのBMI命令の出現により変更されました。

これは、古いプロセッサとの下位互換性を維持しながら、この問題に取り組む良い方法です。

この方法は正しいですが、現在の上位の回答は、エッジの場合に未定義の動作を生成します。

ClangとGCCは、BMI命令を使用して最適化できる場合、gen_mask()を2つの操作に凝縮します。サポートするハードウェアを使用して、BMI命令のコンパイラフラグを必ず追加してください。-mbmi -mbmi2

#include <inttypes.h>
#include <stdio.h>

uint64_t gen_mask(const uint_fast8_t msb) {
  const uint64_t src = (uint64_t)1  << msb;
  return (src - 1) ^ src;
}

int main() {
  uint_fast8_t msb;
  for (msb = 0; msb < 64; ++msb) {
    printf("%016" PRIx64 "\n", gen_mask(msb));
  }
  return 0;
}
8
user2875414

マスクは、ビット単位のAND、OR、XORなどで別の整数値となる整数値の一般的な用語です。

たとえば、int変数の最下位8桁を抽出する場合は、variable & 0xFFを実行します。 0xFFはマスクです。

同様に、ビット0と8を設定する場合は、variable | 0x101を実行します。ここで、0x101はマスクです。

または、同じビットを反転する場合は、variable ^ 0x101を実行します。ここで、0x101はマスクです。

ケースのマスクを生成するには、マスクに1を追加すると(マスクの最下位ビットがすべて1に設定され、残りが0に設定される)、次の累乗の値が得られるという単純な数学的事実を利用する必要があります。 2.2。

したがって、最も近い2の累乗を生成する場合は、そこから1を引いてマスクを取得できます。

2の正の累乗は、Cの左シフト<<演算子を使用して簡単に生成されます。

したがって、1 << nは2を生成しますn。バイナリでは、n0sで10 ... 0です。

(1 << n) - 1は、nの最下位ビットが1に設定されたマスクを生成します。

ここで、左シフトのオーバーフローに注意する必要があります。 C(およびC++)では、変数のビット位置だけ左に変数を合法的にシフトすることはできません。したがって、intが32ビットの場合、1<<32undefined behaviorになります。符号付き整数オーバーフローも回避する必要があるため、符号なし値を使用する必要があります。 1u << 31

8
Alexey Frunze

まず、コードでマスクを作成するだけの場合は、次のようにします。

uint64_t bits = 6;
uint64_t mask = ((uint64_t)1 << bits) - 1;
# Results in 0b111111 (or 0x03F)

マスクとは何かを知りたい人のために:

マスクは通常、AND、OR、XORなどのビット演算を使用して他の値を操作するために使用する値の名前です。

短いマスクは通常バイナリで表され、1に設定されているすべてのビットを明示的に確認できます。

長いマスクは通常16進数で表されます。これは、一度取得すると非常に読みやすくなります。

Cでビット演算の詳細を読むことができます ここ 資料をよりよく理解するために行ってください。

0
Daniel Trugman

あなたの最初の例は0x3fであるべきだと思います。

0x3fは、2進数で63である数値111111の16進表記であるため、最後の6ビット(最下位6ビット)は1に設定されます。

次の小さなCプログラムは、正しいマスクを計算します。

#include <stdarg.h>
#include <stdio.h>

int mask_for_n_bits(int n)
{
    int mask = 0;

    for (int i = 0; i < n; ++i)
        mask |= 1 << i;

    return mask;
}

int main (int argc, char const *argv[])
{
    printf("6: 0x%x\n17: 0x%x\n", mask_for_n_bits(6), mask_for_n_bits(17));
    return 0;
}
0
Torsten

0x2Fはバイナリでは0010 1111です。これは0x3fである必要があります。これは、バイナリでは0011 1111であり、最下位6ビットが設定されています。

同様に、0x1FFFFはバイナリの0001 1111 1111 1111 1111であり、17個の最下位ビットが設定されています。

「マスク」は、&|^などのビット演算子を使用して別の値と組み合わせて、ビットを個別に設定、設定解除、反転、または変更しないことを目的とした値です。その他の値で。

たとえば、0x2F演算子を使用してマスク&をある値nと組み合わせると、結果の最下位6ビットを除くすべてがゼロになり、それらの6ビットは値nから変更せずにコピーされます。

&マスクの場合、マスク内のバイナリ0は「結果ビットを0に無条件に設定する」ことを意味し、1は「結果ビットを入力値ビットに設定する」ことを意味します。 "。 |マスクの場合、マスク内の0は結果ビットを入力ビットに設定し、1は無条件に結果ビットを1に設定し、^マスク、0は結果ビットを入力ビットに設定し、1は結果ビットを入力ビットの補数に設定します。

0
caf