Я знаю основную предпосылку какой побитовой операции (хотя бы оценил объяснение "для чайников" ); однако я не знаю, когда целесообразно использовать эту технику.
Когда выполняются поразрядные операции
Ответ 1
Побитовые операции - отличный способ быстро проверить флаг, который может быть установлен для переменной.
В следующем примере показаны преимущества использования побитовых операций в перечислении Flag
, а также сохранение бит файла в базу данных. Затем бит-битное поле можно легко проверить, чтобы увидеть, содержит ли оно одно значение или подмножество значений из перечисления Flag
.
Пример:
A User
таблица базы данных с полем tinyint
, называемым Permission
. Поле заполняется с использованием значения, созданного с перечислением, значения которого равны 2 ^ n.
[Flags]
public enum Permission : byte
{
None = 0,
ManageUsers = 1 << 0,
CreateOrders = 1 << 1,
PurchaseEquipment = 1 << 2,
CancelOrders = 1 << 3,
}
Помимо побитовых операций, используемых для указания значений в перечислении (выполняется во время компиляции), вы можете использовать перечисление, чтобы проверить, содержит ли поле Permission в базе данных какое-либо подмножество возможных значений. Со стороны базы данных вы получаете возможность вводить значения в одно поле - исключая необходимость наличия столбца для каждого разрешения, а на стороне кода вы получаете простой способ проверить значение.
Пример битстаффинга (Grant ManageUsers и CreateOrders):
Permission userPermissions = Permission.ManageUsers | Permission.CreateOrders;
Проверка разрешения на выбор:
public bool HasPermissions(Permission userPermissions, Permission permissionsToCheckFor)
{
return permissionsToCheckFor == Permission.None ?
false :
(userPermissions & permissionsToCheckFor) == permissionsToCheckFor;
}
Ответ 2
Проблема заключается не в том, что побитовые операции быстрее, чем операции с целыми числами (хотя они обычно есть), что они являются разными операциями для разных целей. p >
Концептуально байты, шорты и ints представляют собой очень маленькие массивы бит, а побитовые операторы - логические операторы массива. В С# в настоящее время побитовые операторы в основном используются для перечислений [Flags]
и в вычислениях для GetHashCode
, но существуют бесконечные способы использования массивов бит.
Ответ 3
Вы правы, потому что язык дает вам побитную операцию, вы не должны использовать их только потому, что можете. Я видел, как люди используют побитовые операторы при работе с простыми булевыми элементами, и это не то, для чего они предназначены.
Побитовые операторы полезны при работе с структурами данных, когда фрагменты данных не выравниваются с границей байта. Как правило, это делается, когда пропускная способность (или общий объем памяти) очень важна. Я работаю над ПО для потоковой передачи видео RTP, а побитовые операции используются как при чтении/построении пакетов передачи RTP, так и для чтения потоков видеокодеков, которые часто кодируются с использованием битов, а не байтов.
Ответ 4
Они могут быть действительно полезны во встроенных ситуациях управления, когда пространство стоит на высоте. Например, один байт данных может представлять 8 битов ввода-вывода, а маски могут использоваться для извлечения интересующих бит из порта ввода-вывода (например, если PIN0 = 1, PIN1 = 2, PIN2 = 4, PIN3 = 8
и т.д., То:
- Чтобы получить значение
PIN0
, мы можем сказатьPORT0 & PIN0 == 0
. - Чтобы установить
PIN1
в 1, мы можем cayPORT0 |= PIN1
. - Чтобы установить
PIN2
в 0, можно сказатьPORT0 &= ~PIN2
.
Вдали от встроенного элемента управления я редко вижу, что этот подход используется в наши дни. В мире С# гораздо чаще встречаются отдельные логические поля для каждого интересующего значения, поскольку накладные расходы действительно не имеют большого значения для современного оборудования (хотя вы можете столкнуться с ситуацией или двумя, где побитовые операции используются для хранения многих таких флаги в одной переменной).
В графике также есть интересное приложение. Чистым трюком для курсоров или ограничивающих прямоугольников является их добавление посредством XOR'ing формы курсора с изображением ниже. Выполнение той же операции снова приведет к исходному изображению.
Ответ 5
Один из способов, по которым я время от времени использую побитовые операторы, - создавать подмножества заданной строки/массива с использованием двоичной маски, он выглядит следующим образом: (извините, код С++)
string s = "abcde";
for(int i = 0; i < 1<<s.size(); i++) {
string tmp;
for(int j = 0; j < s.size(); j++) if(i & 1<<j) tmp.push_back(s[j]);
cout<<tmp<<endl;
}
Возможно, вы захотите проверить этот проницательный совет, ориентированный на конкурсы: Немного веселья: удовольствие с битами