Что такое флаги и битовые поля?
Может кто-нибудь объяснить мне, что такое флаги и битовые поля. Кажется, они связаны друг с другом, или, может быть, я неправильно понял. Я немного разбираюсь в том, что они делают и чем занимаются, но я хотел бы получить их полное объяснение, и я не могу найти хороших учебников или руководств.
Я был бы очень благодарен, если бы кто-нибудь смог привести несколько хороших примеров того, как их использовать и т. Д. Например, я все время вижу подобные выражения и не до конца их понимаю. Просто они какие-то логические операторы или что-то
VARIABLE1 | VARIABLE2
Заранее спасибо!
4 ответа
Введение в побитовые операции можно найти здесь: http://www.codeproject.com/Articles/2247/An-introduction-to-bitwise-operators
Поскольку они применяются к флагам, побитовые операции выгодны тем, что они очень быстрые и экономят место. Вы можете хранить много разных состояний объекта в одной переменной, используя взаимоисключающие биты. т.е.
0001 // property 1 (== 1, 0x01)
0010 // property 2 (== 2, 0x02)
0100 // property 3 (== 4, 0x04)
1000 // property 4 (== 8, 0x08)
Они могут представлять четыре различных свойства объекта (это "маски"). Мы можем добавить свойство в состояние флагов объекта, используя or
:
short objState = 0; // initialize to 0
objState |= 0010;
Это добавляет свойство 2 выше к objState путем "или"-ing-0010 с 0000, что приводит к 0010. Если мы добавим еще один флаг / свойство, например, так:
objState |= 0100;
мы в конечном итоге с objState = 0110.
Теперь мы можем проверить, установлен ли у объекта флаг для свойства 2, например, используя and
:
if (objState & 0010) // do something
and
равен 1, если и только если оба бита равны 1, поэтому, если бит 2 равен 1, вышеуказанная операция гарантированно будет ненулевой.
Итак, как я уже говорил, преимуществами этого способа обработки свойств / флагов объекта являются как скорость, так и эффективность. Подумайте об этом следующим образом: вы можете сохранить набор свойств в одной переменной, используя этот метод.
Допустим, например, что у вас есть тип файла, и вы хотите отслеживать свойства, используя битовые маски (я буду использовать аудиофайлы). Возможно, биты 0–3 могут хранить битовую глубину файла, биты 4–7 могут хранить тип файла (Wav, Aif и т. Д.) И т. Д. Затем вам просто нужна эта одна переменная для передачи различным функциям, и вы можете тестировать, используя ваши определенные битовые маски, вместо того, чтобы отслеживать потенциально десятки переменных.
Надеюсь, что это проливает некоторый свет на хотя бы одно применение побитовой операции.
"Бифилд" - это набор из одного или нескольких битов в "слове" (то есть, скажем, int
, long
или же char
), которые хранятся вместе в одной переменной.
Например, у некоторых животных может быть "нет", "пятна" и / или "полоски", а также может быть хвост "нет, короткий, средний или длинный".
Итак, нам нужно два бита, чтобы отобразить длину хвоста:
enum tail
{
tail_none = 0,
tail_short = 1,
tail_medium = 2,
tail_long = 3
};
Затем мы сохраняем их как биты в "атрибутах":
enum bits_shifts
{
tail_shift = 0, // Uses bits 0..1
spots_shift = 2, // Uses bit 2
stripes_shift = 3
};
enum bits_counts
{
tail_bits = 2, // Uses bits 0..1
spots_bits = 1, // Uses bit 2
stripes_bits = 1
};
Теперь мы притворяемся, что извлекли из некоторого ввода переменные tail_size и has_stripes, has_spots.
int attributes;
attributes = tail_length << tail_shift;
if (has_spots)
{
attributes |= 1 << spots_shift;
}
if (has_stripes)
{
attributes |= 1 << stripes_shift;
}
Позже мы хотим выяснить, что это за атрибуты:
switch((attributes >> tail_shift) & (1 << tail_bits)-1))
{
case tail_none:
cout << "no tail";
break;
case tail_short:
cout << "short tail";
break;
case tail_medium:
cout << "medium tail";
break;
case tail_short:
cout << "long tail";
break;
}
if (attributes & (1 << stripes_shift))
{
cout << "has stripes";
}
if (attributes & (1 << spots_shift))
{
cout << "has spots";
}
Теперь мы сохранили все это в одном целом числе, а затем снова "выловили".
Конечно, вы можете сделать что-то вроде этого:
enum bitfields
{
has_widget1 = 1,
has_widget2 = 2,
has_widget3 = 4,
has_widget4 = 8,
has_widget5 = 16,
...
has_widget25 = 16777216,
...
}
int widgets = has_widget1 | has_widget5;
...
if (widgets & has_widget1)
{
...
}
Это действительно простой способ упаковать несколько вещей в одну переменную.
"Флаг" - это условный объект, который может быть установлен или не установлен, но не является частью языка C++.
Битовое поле - это языковая конструкция для использования наборов битов, которые могут не составлять адресуемый объект. Поля одного бита - это один, часто очень хороший, способ реализации флага.
Биты целочисленного значения могут использоваться как bools.
http://msdn.microsoft.com/en-us/library/yszfawxh(v=vs.80).aspx
Сделать с |
и получить с &
,
enum { ENHANCED_AUDIO = 1, BIG_SPEAKERS = 2, LONG_ANTENNA = 4};
foo(HAS_CAR | HAS_SHOE); // equiv to foo(3);
void processExtraFeatures(flags) {
BOOLEAN enhancedAudio = flags & ENHANCED_AUDIO; // true
BOOLEAN bigSpeakers = flags & BIG_SPEAKERS; // true
BOOLEAN longAntenna = flags & LONG_ANTENNA; // false
}