Удобным решением для получения различного поведения от некоторой функции является использование битовых флагов, которые передаются ей в качестве входных параметров. Давайте разберемся, когда уместно применять и в чем заключается этот прием.
Предположим, нам нужна функция для управления светодиодными индикаторами клавиатуры (Scroll Lock, Num Lock и Caps Lock). Чтобы не усложнять приложение, реализуем его схематично. Будем выводить на консоль состояние, соответствующее переданным битовых флагам. Для этого используем следующую функцию:
творогоизготовитель с прессующими ваннами.
void printLEDState( bool on ) {
if( on ) {
std::cout << " * ";
} else {
std::cout << " _ ";
}
}
Если индикатор включен, то на консоли отобразится символ *, иначе _.
Первым делом определим следующее перечисление:
enum KeyboardLED {
NONE = 0, // 0000
NUM_LOCK = 1, // 0001
CAPS_LOCK = 1 << 1, // 0010
SCROLL_LOCK = 1 << 2, // 0100
ALL = NUM_LOCK | CAPS_LOCK | SCROLL_LOCK // 0111
};
Рядом с каждым значением в виде комментария мы указали его двоичное представление. Обратите внимание, что значения NUM_LOCK
, CAPS_LOCK
и SCROLL_LOCK
выбраны таким образом, что единицы в их бинарном представлении не накладываются. Для определения этих значений мы использовали оператор бинарного сдвига <<
на один бит влево. Это означает, что бинарное умножение любого из них даст в результате ноль, то есть они в совокупности образуют набор битовых флагов.
Еще один интересный прием, который мы здесь наблюдаем, заключается в использовании комбинированного флага ALL
. Он представляет собой побитовое сложение |
всех возможных битовых флагов.
Реализуем саму функцию для установки состояния индикаторов:
void setKeyboardLEDState( unsigned int state ) {
printLEDState( state & NUM_LOCK );
printLEDState( state & CAPS_LOCK );
printLEDState( state & SCROLL_LOCK );
std::cout << std::endl;
}
На вход она принимает параметр state
. Проверка того, должен ли быть включен каждый индикатор или нет, осуществляется с помощью оператора побитового умножения &
. Например, для CAPS_LOCK
мы видим:
state & CAPS_LOCK
Если биты в state
и CAPS_LOCK
наложатся, то в функцию printLEDState()
будет передана истина, иначе ложь.
Рассмотрим пример, чтобы лучше понять, как это работает. Передадим функции setKeyboardLEDState()
параметр state
, равный NUM_LOCK | CAPS_LOCK
(то есть 0001 | 0010 = 0011
). Во время проверок state & NUM_LOCK
(0011 & 0001 = 0001
) и state & CAPS_LOCK
(0011 & 0010 = 0010
) мы видим, что единицы в бинарном представлении накладываются и получаются ненулевые значения, которые соответствуют true
. Однако в последней проверке state & SCROLL_LOCK
(0011 & 0100 = 0000
) получается ноль, который соответствует false
. В результате на экран будет выведено: * * _
.
А вот еще несколько примеров запуска с указанием результатов, которые будут выведены на консоль:
setKeyboardLEDState( NONE ); // _ _ _
setKeyboardLEDState( NUM_LOCK | CAPS_LOCK ); // * * _
setKeyboardLEDState( ALL ); // * * *
Использование битовых флагов - довольно удобный и одновременно мощный прием. Его сильной чертой является возможность комбинирования различных режимов работы. Но прежде, чем использовать описанный метод, изучите следующую заметку: Указатели на функции в C++. В ней продемонстрирован более гибкий подход к параметризации поведения функций, который может подойти для решения вашей задачи еще лучше.
Anonymous
Спасибо за статью, было полезно освежить в памяти.