Что такое флаги и битовые поля?

Может кто-нибудь объяснить мне, что такое флаги и битовые поля. Кажется, они связаны друг с другом, или, может быть, я неправильно понял. Я немного разбираюсь в том, что они делают и чем занимаются, но я хотел бы получить их полное объяснение, и я не могу найти хороших учебников или руководств.

Я был бы очень благодарен, если бы кто-нибудь смог привести несколько хороших примеров того, как их использовать и т. Д. Например, я все время вижу подобные выражения и не до конца их понимаю. Просто они какие-то логические операторы или что-то

  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
}
Другие вопросы по тегам