2012-09-14 7 views
12

この機能を私に説明してもらえますか?Cで最小のビット数が1に設定されたマスクを作成するには

1.

例に設定最下位nビットでマスク:

のn = 6 - 私がこれらを得ることはありません> 0x1FFFF // - > 0x2F、N = 17すべて、特にどのようにn = 6 - > 0x2F

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

+3

*また、マスクは何ですか*(http://en.wikipedia.org/wiki/Mask_ (コンピューティング)) – chris

+1

0x2fは間違っています。0x3f – wich

+1

@chris wikiはあまりにも混乱しています... – sebi

答えて

22

普通の方法は1をとり、それを左にシフトしてnビットです。それはあなたに何かを与える:00100000。それから1を引いて、設定されているビットをクリアし、すべての下位ビットを設定します。この場合は、00011111となります。

通常、マスクはビット単位の操作で使用されます。特にandです。上記のマスクを使用して、5つの最下位ビットを単独で取得し、存在する可能性のあるものから隔離します。これは、多くの場合、単一のハードウェアレジスタを持ち、多くの完全に別々の数量やフラグを表すビットを含むハードウェアを扱う場合に一般的です。

+2

'1 << w-1'に行くことに留意してください。' w'は幅ビットの1つを除くすべてを設定するデータ型はUBです。 – chris

+0

正確に。インテルでそれを非難するが、それは標準にした。 – wildplasser

+0

この方法でUBから一様に回復する方法については、下記の私の答えを参照してください。 – user13972

0

あなたの最初の例は0x3fであるはずです。

0x3fは、最後の6ビット(最下位6ビット)1に設定されるように、バイナリで111111で数63の16進表記です。

以下少し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

0x2Fはバイナリで0010 1111である - これはバイナリで0011 1111と設定6最下位ビットを有する0x3f、であるべきです。

同様に、0x1FFFFは、2進数で0001 1111 1111 1111 1111であり、最下位17ビットが設定されている。

A「マスク」は、他の値のビットを反転または変化しないまま、解除、個別に設定する&|又は^ようなビット単位の演算子を使用して別の値と結合されることが意図されている値です。例えば

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

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

+0

Ops。更新後に間違った編集をしましたが、ロールバックしました。ごめんなさい! – jweyrich

5

マスクは、別の整数値とビット単位の論理積、論理和、排他的論理和などの一般的な用語です。

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

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

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

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

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

正のパワーを容易したがってC.

における左シフト<<オペレータ、1 << n収量2 Nで生成されます。バイナリではそれは0 ... nで0 ... 0です。

(1 << n) - 1今すぐ1

に設定n最下位ビットでマスクが生成されます、あなたは左シフトでオーバーフローに注意する必要があります。 C(およびC++)では、変数が持つビット位置の数だけ合法的にシフトすることはできません。したがって、intが32ビットの場合、1<<32の結果はundefined behaviorとなります。符号付き整数オーバーフローも避ける必要があります。したがって、符号なしの値を使用する必要があります。 1u << 31

7

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

古いプロセッサとの下位互換性を維持しながら、この問題に近づける良い方法があります。

この方法は正しいですが、現在のトップの回答では、エッジのケースでは未定義の動作が発生します。

BMI命令を使用して最適化することを許可されている場合、ClangとGCCはgen_mask()をわずか2 opsに圧縮します。ハードウェアのサポートに、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; 
} 
+0

オフライン・ワンのエラーAFAICTがあります。 –

+1

申し訳ありませんが、それは誤解です:私はOPとして言及したNのようなパラメータとして幅を使用していたでしょうが、MSBのインデックスを使用するので、実際には一貫しています。 –

+0

この場合、constingは何をしますか? –