바이트에서 특정 비트 가져 오기


97

나는 바이트, 특히 다른 장치에서 보낸 UDP를 통해 들어온 바이트 배열에서 한 바이트가 있습니다. 이 바이트는 장치에있는 8 개의 릴레이의 켜짐 / 꺼짐 상태를 저장합니다.

해당 바이트에서 특정 비트의 값을 어떻게 얻습니까? 이상적으로는 확장 방법이 가장 우아하게 보이고 bool을 반환하는 것이 가장 의미가 있습니다.

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

답변:


179

쉬운. 비트 AND를 사용하여 숫자를 비트 이동으로 저렴하게 계산할 수있는 2 ^ bitNumber 값과 비교합니다.

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

편집 : 설명이없는 유사한 답변이 많기 때문에 조금 더 자세히 추가하려면 :

비트 AND는 AND 조인을 사용하여 각 숫자를 비트별로 비교하여 해당 위치의 첫 번째 비트와 두 번째 비트가 모두 설정된 비트 조합 인 숫자를 생성합니다. 다음은 비트 AND의 연산을 보여주는 "니블 (nibble)"의 AND 논리의 논리 행렬입니다.

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

귀하의 경우에는 귀하가 전달한 숫자를 찾고자하는 비트 만있는 숫자와 비교합니다. 네 번째 비트를 찾고 있다고 가정 해 보겠습니다.

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

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

비교하고자하는 숫자를 생성하는 비트 시프 팅은 정확히 들리는 것입니다. 비트 세트로 표현 된 숫자를 취하고 특정 자리 수만큼 해당 비트를 왼쪽 또는 오른쪽으로 이동합니다. 이것들은 이진수이고 각 비트는 오른쪽의 것보다 2의 거듭 제곱이 더 크므로 왼쪽으로 비트 이동은 이동 된 각 위치에 대해 한 번 숫자를 두 배로 늘리는 것과 같습니다. 2 ^ x. 귀하의 예에서 네 번째 비트를 찾고 다음을 수행합니다.

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

이제 어떻게 이루어 졌는지, 낮은 수준에서 무슨 일이 일어나고 있는지, 왜 작동하는지 알 수 있습니다.


8
중괄호 (연산자 우선 순위)가 누락 되었기 때문에이 코드는 컴파일되지 않으므로 var bit = (b & (1 << bitNumber-1)) != 0;
bitbonk

54

Josh의 대답을 읽고 이해하는 것이 좋지만 Microsoft가이 목적으로 제공 한 클래스 인 System.Collections.BitArray 를 사용하는 것이 더 행복 할 것입니다 . 모든 버전의 .NET Framework에서 사용할 수 있습니다.


1
이것은 훌륭하지만 Josh의 솔루션이 훨씬 빠르고 효율적이라고 생각합니다.
Samuel Allan

1
@ user2332868 : JIT 컴파일러는 특정 라이브러리 함수에 대한 호출을 특별히 인식하고 효율적인 코드를 생성하지만 이러한 특정 함수가 사랑을 받는지 모르겠습니다.
Ben Voigt 2014

1
Josh와 동일하지만 순수 인라인 어셈블리에서 수행 할 수 있는지 확인하십시오. 그러나 NASM에서 슬프게도 나는 유일한 프로그램은 어셈블리로 :( 어셈블리 C에 대해 # 컴파일을 모른다.
사무엘 앨런

1
IMHO는 이러한 간단한 작업의 성능을 저하시킵니다. 또한 비트 연산자를 대체 사용) = 거의 모든 언어로 그것을 사용할 수있는 당신에게 도구를 제공합니다
Gaspa79

38

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

해야한다고 생각합니다.


9

그것을하는 또 다른 방법 :)

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

1
작동하지 않습니다 : byte b = 1; return ((b >> 1) & 1)! = 0 (0과 같음)
Rafael Diego Nicoletti 2014

1
흠 .. 이해가 안 돼요. 바이트 b = 1 인 경우 위치 0의 비트는 (b >> 0) & 1에 의해 제공되는 1이고, 1보다 크거나 같은 위치의 비트는 (b >> n) & 1에 의해 제공되며, 여기서 n> = 1입니다. 뿐만 아니라
PierrOz 2014

나는 그가 그것을 전혀 믿지 않는다 @DavideAndrea, Rafael이 게시 한 코멘트는 가장 오른쪽 비트가 비트 1이라고 가정하지만 PierrOz의 코드는 가장 오른쪽 비트가 비트 0 일 때 ((2 >> 1)&1)입니다. b가 2이면 다음 1과 같습니다. ((2 >> 0)&1)있다 02이기 때문입니다00000010
카메론 Aavik


6

BitArray 클래스를 사용 하고 OP가 제안하는대로 확장 메서드를 만듭니다.

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


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.