Я использую UInt64
для хранения битов. Примером может быть UInt64 val = 0b0001_0000
. Теперь я хочу иметь возможность определить, установлен ли бит в определенной позиции. Например, я хотел бы знать, установлен ли 4-й бит (с использованием индексации с нуля) в val
. Если бы я жестко закодировал это, я мог бы просто использовать операторы AND и OR для работы с временной переменной, очищая все биты, кроме четвертого, и проверяя значение. Однако я хотел бы реализовать более динамичный способ сделать это, поэтому мне не нужно использовать кучу разных битовых литералов, таких как 0b0001_0000
, для небольшой проверки.
Я пробовал разобрать строку типа "0b0001_0000"
, которая создается динамически, но мне не повезло с UInt64
, Byte
и т. д.
Или используйте класс BitArray
вы используете оператор Left (<<) или Right (>>) для перехода по битам к большему числовому значению для всех int, long, uint, ulong и т. д.
См. Эту статью в документации MSDN: Оператор левого сдвига и Оператор правого сдвига
Вот так (я взял пример со страницы оператора левого сдвига):
class MainClass
{
static void Main()
{
int i = 1;
long lg = 1;
// Shift i one bit to the left. The result is 2.
Console.WriteLine("0x{0:x}", i << 1);
// In binary, 33 is 100001. Because the value of the five low-order
// bits is 1, the result of the shift is again 2.
Console.WriteLine("0x{0:x}", i << 33);
// Because the type of lg is long, the shift is the value of the six
// low-order bits. In this example, the shift is 33, and the value of
// lg is shifted 33 bits to the left.
// In binary: 10 0000 0000 0000 0000 0000 0000 0000 0000
// In hexadecimal: 2 0 0 0 0 0 0 0 0
Console.WriteLine("0x{0:x}", lg << 33);
}
}
/*
Output:
0x2
0x2
0x200000000
*/
ОБНОВИТЬ:
А еще лучше посмотрите эту полную реализацию (основанную на структуре BYTE - просто измените ее на LONG или ULONG) с этого сайта Битовая обработка в C:
ОБНОВЛЕНИЕ 2:
В итоге мне очень понравилась статья Битовая обработка в C, я реализовал ее класс (основанный на байтах) и немного улучшил, превратив его в класс со множеством методов и интерфейсов. Вот оно:
namespace System
{
public class BitCheck8 : global::System.IEquatable<byte>, global::System.IEquatable<global::System.BitCheck8>, global::System.Collections.Generic.IEnumerable<bool>, global::System.Collections.Generic.IDictionary<int, bool>
{
public const byte Empty = 0x0;
protected byte Control;
protected static global::System.ArgumentOutOfRangeException OutOfRange() { return new global::System.ArgumentOutOfRangeException("pos", "Argument [Pos] not between 0-7"); }
public static bool IsBitSet(byte b, int pos) { if (pos < 0 || pos > 7) { throw global::System.BitCheck8.OutOfRange(); } else { return (b & (1 << pos)) != 0; } }
public static byte SetBit(byte b, int pos) { if (pos < 0 || pos > 7) { throw global::System.BitCheck8.OutOfRange(); } else { return (byte)(b | (1 << pos)); } }
public static byte UnsetBit(byte b, int pos) { if (pos < 0 || pos > 7) { throw global::System.BitCheck8.OutOfRange(); } else { return (byte)(b & ~(1 << pos)); } }
public static byte ToggleBit(byte b, int pos) { if (pos < 0 || pos > 7) { throw global::System.BitCheck8.OutOfRange(); } else { return (byte)(b ^ (1 << pos)); } }
public static string ToBinaryString(byte b) { return global::System.Convert.ToString(b, 2).PadLeft(8, '0'); }
public virtual bool IsReadOnly { get { return false; } }
public byte Base { get { return this.Control; } set { if (!this.IsReadOnly) { this.Control = value; } } }
public bool IsBitSet(int pos) { return global::System.BitCheck8.IsBitSet(this.Control, pos); }
public void SetBit(int pos) { if (!this.IsReadOnly) { this.Control = global::System.BitCheck8.SetBit(this.Control, pos); } }
public void UnsetBit(int pos) { if (!this.IsReadOnly) { this.Control = global::System.BitCheck8.UnsetBit(this.Control, pos); } }
public void ToggleBit(int pos) { if (!this.IsReadOnly) { this.Control = global::System.BitCheck8.ToggleBit(this.Control, pos); } }
public void Clear() { if (!this.IsReadOnly) { this.Control = global::System.BitCheck8.Empty; } }
public override string ToString() { return global::System.BitCheck8.ToBinaryString(this.Control); }
public bool this[int pos] { get { return this.IsBitSet(pos); } set { if (value) { this.SetBit(pos); } else { this.UnsetBit(pos); } } }
public bool Check0 { get { return this[0]; } set { this[0] = value; } }
public bool Check1 { get { return this[1]; } set { this[1] = value; } }
public bool Check2 { get { return this[2]; } set { this[2] = value; } }
public bool Check3 { get { return this[3]; } set { this[3] = value; } }
public bool Check4 { get { return this[4]; } set { this[4] = value; } }
public bool Check5 { get { return this[5]; } set { this[5] = value; } }
public bool Check6 { get { return this[6]; } set { this[6] = value; } }
public bool Check7 { get { return this[7]; } set { this[7] = value; } }
public global::System.Collections.Generic.IEnumerator<bool> GetEnumerator() { for (int pos = 0; pos < 8; pos++) { yield return this.IsBitSet(pos); } }
global::System.Collections.IEnumerator global::System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); }
bool global::System.IEquatable<byte>.Equals(byte b) { return this.Control == b; }
public override bool Equals(object obj) { return base.Equals(obj); }
public bool Equals(global::System.BitCheck8 obj) { return base.Equals(obj); }
public override int GetHashCode() { return base.GetHashCode(); }
void global::System.Collections.Generic.ICollection<global::System.Collections.Generic.KeyValuePair<int, bool>>.Add(global::System.Collections.Generic.KeyValuePair<int, bool> item) { this[item.Key] = item.Value; }
bool global::System.Collections.Generic.ICollection<global::System.Collections.Generic.KeyValuePair<int, bool>>.Contains(global::System.Collections.Generic.KeyValuePair<int, bool> item) { return this[item.Key]; }
int global::System.Collections.Generic.ICollection<global::System.Collections.Generic.KeyValuePair<int, bool>>.Count { get { return 8; } }
bool global::System.Collections.Generic.ICollection<global::System.Collections.Generic.KeyValuePair<int, bool>>.Remove(global::System.Collections.Generic.KeyValuePair<int, bool> item) { return false; }
void global::System.Collections.Generic.IDictionary<int, bool>.Add(int Key, bool Value) { this[Key] = Value; }
bool global::System.Collections.Generic.IDictionary<int, bool>.ContainsKey(int Key) { return (Key > -1 && Key < 8); }
bool global::System.Collections.Generic.IDictionary<int, bool>.Remove(int Key) { return false; }
global::System.Collections.Generic.IEnumerator<global::System.Collections.Generic.KeyValuePair<int, bool>> global::System.Collections.Generic.IEnumerable<global::System.Collections.Generic.KeyValuePair<int, bool>>.GetEnumerator() { for (int pos = 0; pos < 8; pos++) { yield return new global::System.Collections.Generic.KeyValuePair<int, bool>(pos, this[pos]); } }
void global::System.Collections.Generic.ICollection<global::System.Collections.Generic.KeyValuePair<int, bool>>.CopyTo(global::System.Collections.Generic.KeyValuePair<int, bool>[] array, int index) { global::System.Array.Copy(new global::System.Collections.Generic.KeyValuePair<int, bool>[] { new global::System.Collections.Generic.KeyValuePair<int, bool>(0, this[0]), new global::System.Collections.Generic.KeyValuePair<int, bool>(1, this[1]), new global::System.Collections.Generic.KeyValuePair<int, bool>(2, this[2]), new global::System.Collections.Generic.KeyValuePair<int, bool>(3, this[3]), new global::System.Collections.Generic.KeyValuePair<int, bool>(4, this[4]), new global::System.Collections.Generic.KeyValuePair<int, bool>(5, this[5]), new global::System.Collections.Generic.KeyValuePair<int, bool>(6, this[6]), new global::System.Collections.Generic.KeyValuePair<int, bool>(7, this[7]) }, 0, array, index, 8); }
global::System.Collections.Generic.ICollection<int> global::System.Collections.Generic.IDictionary<int, bool>.Keys { get { return (global::System.Collections.Generic.ICollection<int>)new int[] { 0, 1, 2, 3, 4, 5, 6, 7 }; } }
global::System.Collections.Generic.ICollection<bool> global::System.Collections.Generic.IDictionary<int, bool>.Values { get { return (global::System.Collections.Generic.ICollection<bool>)new bool[] { this[0], this[1], this[2], this[3], this[4], this[5], this[6], this[7] }; } }
public static bool operator ==(global::System.BitCheck8 obj1, global::System.BitCheck8 obj2) { return (obj1 != null && obj2 != null && obj1.Control == obj2.Control); }
public static bool operator !=(global::System.BitCheck8 obj1, global::System.BitCheck8 obj2) { return (obj1 == null || obj2 == null || obj1.Control != obj2.Control); }
public static bool operator ==(global::System.BitCheck8 obj1, byte obj2) { return (obj1 != null && obj1.Control == obj2); }
public static bool operator !=(global::System.BitCheck8 obj1, byte obj2) { return (obj1 == null || obj1.Control != obj2); }
bool global::System.Collections.Generic.IDictionary<int, bool>.TryGetValue(int Key, out bool Value)
{
Value = false;
if (Key > -1 && Key < 8)
{
Value = this.IsBitSet(Key);
return true;
} else { return false; }
}
public static global::System.BitCheck8 operator +(global::System.BitCheck8 obj1, byte obj2)
{
if (obj1 == null) { return new global::System.BitCheck8(obj2); }
else
{
global::System.BitCheck8 a = new global::System.BitCheck8(obj1.Control);
for (int pos = 0; pos < 8; pos++) { if (global::System.BitCheck8.IsBitSet(obj2, pos)) { a[pos] = true; } }
return a;
}
}
public static global::System.BitCheck8 operator -(global::System.BitCheck8 obj1, byte obj2)
{
if (obj1 == null) { return new global::System.BitCheck8(obj2); }
else
{
global::System.BitCheck8 a = new global::System.BitCheck8(obj1.Control);
for (int pos = 0; pos < 8; pos++) { if (!global::System.BitCheck8.IsBitSet(obj2, pos)) { a[pos] = false; } }
return a;
}
}
public static global::System.BitCheck8 operator +(global::System.BitCheck8 obj1, global::System.BitCheck8 obj2) { return (obj2 == null ? obj1 : (obj1 + obj2.Control)); }
public static global::System.BitCheck8 operator -(global::System.BitCheck8 obj1, global::System.BitCheck8 obj2) { return (obj2 == null ? obj1 : (obj1 - obj2.Control)); }
public BitCheck8(bool Check0, bool Check1 = false, bool Check2 = false, bool Check3 = false, bool Check4 = false, bool Check5 = false, bool Check6 = false, bool Check7 = false)
{
this.Control = 0x0;
this[0] = Check0;
this[1] = Check1;
this[2] = Check2;
this[3] = Check3;
this[4] = Check4;
this[5] = Check5;
this[6] = Check6;
this[7] = Check7;
}
public BitCheck8(byte check) { this.Control = check; }
public BitCheck8() { this.Clear(); }
}
}
Используйте оператор битового сдвига, чтобы преобразовать индекс в беззнаковый длинный:
ulong bitIndexValue = 1ul << index;
// bitIndexValue = 0b0001 if index equals 0
// bitIndexValue = 0b0010 if index equals 1
// bitIndexValue = 0b0100 if index equals 2
Убедитесь, что у вашего unsigned long один и тот же бит установлен в единицу:
( value & bitIndexValue) == bitIndexValue;
// ( 0b0101 & 0b0100 ) == 0b0100 if index equals 2
Вот полный метод:
static bool CheckBit(ulong value, byte index)
{
if (index < 0 || index > 63) throw new ArgumentOutOfRangeException("index");
ulong bitIndexValue = 1UL << index;
return (value & bitIndexValue) == bitIndexValue;
}
И как им пользоваться:
Assert.IsTrue(CheckBit(4ul, 2)); // 0b0100 does contain 0b0100
Assert.IsTrue(CheckBit(5ul, 2)); // 0b0101 does contain 0b0100
Assert.IsFalse(CheckBit(8ul, 2)); // 0b1000 does not contain 0b0100
Если вы хотите проверить, установлен ли бит, используйте
x & (1 << bitNumber) != 0
, чтобы установить его, используйтеx |= 1 << bitNumber
для расчета битовых масок на лету.