IT story

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

hot-time 2020. 9. 10. 18:58
반응형

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


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

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

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

쉬운. 비트 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

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


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


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

해야한다고 생각합니다.


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

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

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

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

이 시도:

return (b & (1 << bitNumber))>0;

이것은 0.1 밀리 초보다 빠르게 작동합니다.

return (b >> bitNumber) & 1;

방법은 비트 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;
    }
}

아래 코드를 시도하십시오. 다른 게시물과 다른 점은 마스크 ( 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

[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);
}

참고 URL : https://stackoverflow.com/questions/4854207/get-a-specific-bit-from-byte

반응형