Как перевернуть значение одного бита?

Я буду честен, это домашнее задание, которое я просто не могу сделать. Задача состоит в том, чтобы обработать 8 разных флажков, используя один байт. Конструктор формы, которая содержит флажки, принимает байт в качестве входных данных и устанавливает флажки в положение «отмечено» на основе ввода. Затем байт флага где-то сохраняется, и после этого каждый раз, когда один флажок меняет свой статус (с отмеченного на непроверенный и с непроверенного на отмеченный), я должен соответствующим образом изменить байт флага. Пока смог сделать только первую часть:

public Form1(byte flags)
{
    InitializeComponent();
    flags2 = flags;
    if ((flags & 0x01) >> 0 != 0) checkBox1.Checked = true; 
    if ((flags & 0x02) >> 1 != 0) checkBox2.Checked = true; 
    if ((flags & 0x04) >> 2 != 0) checkBox3.Checked = true; 
    if ((flags & 0x08) >> 3 != 0) checkBox4.Checked = true; 
    if ((flags & 0x10) >> 4 != 0) checkBox4.Checked = true;
    if ((flags & 0x20) >> 5 != 0) checkBox6.Checked = true; 
    if ((flags & 0x40) >> 6 != 0) checkBox7.Checked = true;
    if ((flags & 0x80) >> 7 != 0) checkBox8.Checked = true; 
}    

Но я действительно не знаю, как сделать не только 1 бит. Я думал об использовании дополнений, но тогда остальные меняют биты влево. Я могу использовать этот трюк только в самом важном месте, где отдых не имеет последствий.

private void checkBox8_CheckedChanged(object sender, EventArgs e)
{
    flags2 += 0x80;
}       

Для других битов я действительно мог бы использовать некоторую помощь.


person user1909612    schedule 10.05.2013    source источник


Ответы (4)


Вы должны инвертировать битовую маску:

flags &= ~0x10

установит бит 4 (0x10) в 0.
Оператор ~ инвертирует все биты (пример 8 бит):

 0x10 (0001000)
~0x10 (1110111)

Чтобы немного переключить, используйте это (xor):

flags ^= 0x10

Использование сложений никогда не работает, если вы хотите работать с битами.
Для практики я рекомендую записывать все числа в виде битовых масок: 0x10 = 0001000 (основание 2)

person joe    schedule 10.05.2013
comment
сейчас тестирую, сообщу, работает ли. edit: это не сработало, оператор ~ можно использовать только для байта:/ - person user1909612; 11.05.2013
comment
Оператор ~ определен для любых целых чисел (byte, short, int,...) - person joe; 11.05.2013
comment
Сложение иногда работает, если вы работаете с битами.. не если вы хотите xor (также известное как сложение без переноса), конечно, но, например, x & (x - 1) (вычитание - это форма сложения), чтобы удалить самую правую 1, и некоторые другие выражения, включающие крайнюю правую биты, используйте сложение (или вычитание) таким образом, который имеет смысл для битового вектора. - person harold; 11.05.2013
comment
@harold: ты совершенно прав. Я считаю это опасным, потому что вы можете только один раз сложить и один раз вычесть. В большинстве случаев я только устанавливаю или сбрасываю бит, независимо от того, как часто - поэтому битовые операции безопасны. - person joe; 11.05.2013
comment
Я не уверен, что это соответствует тому, что я сказал, но уверен, что добавление - не очень хороший способ установить биты. И, например, тождество (x | y) == (x & ~y) + y не очень полезно, так как требует больше операций. - person harold; 11.05.2013

Для переключения битов используйте оператор XOR (^):

flags ^= <bits>;   -or-  flags2 = flags ^ <bits>;   -e.g.-  flags ^= 0x04;

Чтобы установить биты, используйте оператор ИЛИ (|):

flags |= <bits>;   -or-  flags2 = flags | <bits>;   -e.g.-  flags |= 0x08;

Чтобы очистить биты, используйте оператор И (&) и оператор НЕ (~).

flags &= ~<bits>;  -or-  flags2 = flags & ~<bits>;  -e.g.-  flags &= ~0x08;
person Michael Gunter    schedule 10.05.2013

Предположим, что переменная, в которой вы сохранили начальный статус, имеет значение flags2, тогда

private void CheckBox1_CheckedChanged(Object sender, EventArgs e) 
{
   if(checkBox1.Checked)
       flags2 |= 1;
   else
       flags2 &= ~0xFE; 

   // ~0x2=0xFD, ~0x4=0xFB, ~0x08=0xF7, 
   // ~0x10=0xF5, ~0x20=0xEB, ~0x40=0xD7, ~0x80=0xAF
}

Также обратите внимание, что ваш первоначальный тест можно было бы переписать просто как

if ((flags & 0x04) != 0) checkBox1.Checked = true; 
person Steve    schedule 10.05.2013
comment
тестирую это решение прямо сейчас, я дам вам знать, если оно работает - person user1909612; 11.05.2013
comment
не сработало, если сложение находится между двумя положительными битами, есть остаток, который изменяет все последовательные биты:/ - person user1909612; 11.05.2013
comment
ну, на самом деле, я не смог проверить это, мне пришлось сделать это, что больше похоже на ваше решение, чем на решение Джо. если (checkBox1.Checked) flags2 |= 0x01; иначе flags2 = (byte)(flags2 & (~0x01)); Что мне теперь делать ? Я уже принял его ответ на скорую руку - person user1909612; 11.05.2013
comment
А, ну, случай Самое быстрое оружие на Западе. Это тебе решать. Вы можете не принять и принять другой ответ, если считаете, что он лучше. Это происходит каждый день. На самом деле я не уверен, что разрешено с вашими представителями. Но, в любом случае, вы можете изменить принятие, когда у вас будет достаточно повторений, и, конечно, вы всегда можете проголосовать за частичные полезные ответы. - person Steve; 11.05.2013

Кроме того, вы можете упростить код инициализации:

checkBox1.Checked = ((flags & 0x01) != 0);
checkBox2.Checked = ((flags & 0x02) != 0);
checkBox3.Checked = ((flags & 0x04) != 0);
checkBox4.Checked = ((flags & 0x08) != 0);
checkBox5.Checked = ((flags & 0x10) != 0);
checkBox6.Checked = ((flags & 0x20) != 0);
checkBox7.Checked = ((flags & 0x40) != 0);
checkBox8.Checked = ((flags & 0x80) != 0);
person Michael Gunter    schedule 10.05.2013