バイトから特定のビットを取得する


97

1バイト、具体的には、別のデバイスから送信されたUDPを介して受信したバイト配列から1バイトです。このバイトは、デバイス内の8つのリレーのオン/オフ状態を格納します。

上記のバイトの特定のビットの値を取得するにはどうすればよいですか?理想的には、拡張メソッドが最もエレガントに見え、ブール値を返すことが私にとって最も理にかなっています。

public static bool GetBit(this byte b, int bitNumber)
{
    //black magic goes here
}

回答:


178

簡単です。ビットごとのANDを使用して、数値を値2 ^ bitNumberと比較します。これは、ビットシフトによって安価に計算できます。

//your black magic
var bit = (b & (1 << bitNumber-1)) != 0;

編集:説明のない同様の答えがたくさんあるので、もう少し詳細を追加するには:

ビットごとのANDは、各数値をビットごとに比較し、AND結合を使用して、その場所の最初のビットと2番目のビットの両方が設定されたビットの組み合わせである数値を生成します。以下は、ビットごとのANDの演算を示す「ニブル」内のAND論理の論理行列です。

  0101
& 0011
  ----
  0001 //Only the last bit is set, because only the last bit of both summands were set

あなたの場合、私たちはあなたが渡した数を、あなたが探したいビットだけがセットされている数と比較します。あなたが4番目のビットを探しているとしましょう:

  11010010
& 00001000
  --------
  00000000 //== 0, so the bit is not set

  11011010
& 00001000
  --------
  00001000 //!= 0, so the bit is set

比較する数値を生成するためのビットシフトは、まさにそのように聞こえます。ビットのセットとして表される数値を受け取り、それらのビットを特定の数の場所で左または右にシフトします。これらは2進数であり、各ビットは右側のビットよりも2のべき乗が大きいため、左側へのビットシフトは、シフトされる各場所で1倍の数に相当し、数値を乗算するのと同じです。 2 ^ x。あなたの例では、4番目のビットを探して、以下を実行します。

       1 (2^0) << (4-1) ==        8 (2^3)
00000001       << (4-1) == 00001000

これで、それがどのように行われ、低レベルで何が起こっているのか、なぜ機能するのかがわかりました。


8
中かっこ(演算子の優先順位)がないため、このコードはコンパイルされませんvar bit = (b & (1 << bitNumber-1)) != 0
bitbonk 2012

54

Joshの回答を読んで理解するのは良いことですが、おそらく、この目的のためにMicrosoftが提供するクラスSystem.Collections.BitArrayを使用するほうが楽でしょう 。これは、.NET Frameworkのすべてのバージョンで利用できます。


1
これはすばらしいですが、ジョシュのソリューションははるかに高速で効率的だと思います。
Samuel Allan 14

1
@ user2332868:JITコンパイラーは、特定のライブラリー関数への呼び出しを特別に認識し、効率的なコードを生成しますが、これらの特定の関数に愛着があるかどうかはわかりません。
Ben Voigt 2014

1
Joshと同じことができるが、純粋なインラインアセンブリで実行できることを確認してください。しかし残念なことに、私はNASMアセンブリでのみプログラミングし、C#が:(。にコンパイルするアセンブリについて知りません。–
Samuel Allan

1
私見これはそのような単純なタスクのパフォーマンスを殺します。ビットワイズ演算子の代替を使用すると、ほとんどすべての言語でそれを使用できるツールも提供されます=)
Gaspa79

38

この

public static bool GetBit(this byte b, int bitNumber) {
   return (b & (1 << bitNumber)) != 0;
}

そうすべきだと思います。


9

それを行う別の方法:)

return ((b >> bitNumber) & 1) != 0;

1
これは機能しません:バイトb = 1; return((b >> 1)&1)!= 0(0と等しい)
Rafael Diego Nicoletti

1
うーん...私はあなたを理解していません。バイトb = 1の場合、(b >> 0)&1によって与えられる位置0のビットは1であり、(b >> n)&1によって与えられる1以上の任意の位置のビットはn> = 1同様に
PierrOz 2014年

私はその後、彼はすべての@DavideAndreaで、ラファエルで掲示コメントは一番右のビットがビット1であると仮定しますが、bが2だった場合PierrOzのコードは、右端のビットはビット0のときのためのものであることないとは考えていない((2 >> 1)&1)です1し、((2 >> 0)&1)ある02であるため00000010
キャメロンAavik


6

OPが示唆するようにBitArrayクラスを使用し、拡張メソッドを作成する:

public static bool GetBit(this byte b, int bitNumber)
{
    System.Collections.BitArray ba = new BitArray(new byte[]{b});
    return ba.Get(bitNumber);
}

9
いいえ、ビットテストごとにBitArrayを作成して破棄しないでください。
Ben Voigt 2014年

@BenVoigt、これはOPリクエストごとのバイトの拡張メソッドです。BitArrayインスタンスをどこに保存することをお勧めしますか?
Jay Walker

2
あなたはリクエストを拒否して、バイトのメソッドのように呼び出すのではなく、BitArrayで呼び出します。たぶん、バイト変数は完全になくなるでしょう。
Ben Voigt 2014年

バイトのn番目のビットを取得しようとしている場合は、パフォーマンスを求めている可能性が高く、これはそれを殺します。それ以外の場合は、Convert.ToString(num、2)[bitNumber]などの他の不要な処理を常に実行して取得することもできます。
Gaspa79 2017


3

この方法では、別のバイトをビットごとのANDとともに使用して、ターゲットビットをマスクします。

ここでのクラスの規則を使用しました。「0」が最上位ビット、「7」が最小ビットです。

public static class ByteExtensions
{
    // Assume 0 is the MSB andd 7 is the LSB.
    public static bool GetBit(this byte byt, int index)
    {
        if (index < 0 || index > 7)
            throw new ArgumentOutOfRangeException();

        int shift = 7 - index;

        // Get a single bit in the proper position.
        byte bitMask = (byte)(1 << shift);

        // Mask out the appropriate bit.
        byte masked = (byte)(byt & bitMask);

        // If masked != 0, then the masked out bit is 1.
        // Otherwise, masked will be 0.
        return masked != 0;
    }
}

3

以下のコードを試してください。他の投稿との違いは、マスク(field)を使用して複数のビットを設定/取得できることです。4番目のビットのマスクは、たとえば1 << 3、または0x10にすることができます。

    public int SetBits(this int target, int field, bool value)
    {
        if (value) //set value
        {
            return target | field;
        }
        else //clear value
        {
            return target & (~field);
        }
    }

    public bool GetBits(this int target, int field)
    {
        return (target & field) > 0;
    }

**例**

        bool is_ok = 0x01AF.GetBits(0x10); //false
        int res = 0x01AF.SetBits(0x10, true);
        is_ok = res.GetBits(0x10);  // true

2
[Flags]
enum Relays : byte
{
    relay0 = 1 << 0,
    relay1 = 1 << 1,
    relay2 = 1 << 2,
    relay3 = 1 << 3,
    relay4 = 1 << 4,
    relay5 = 1 << 5,
    relay6 = 1 << 6,
    relay7 = 1 << 7
}

public static bool GetRelay(byte b, Relays relay)
{
    return (Relays)b.HasFlag(relay);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.