на перечислении и побитовой операции - PullRequest
6 голосов
/ 20 октября 2011

Возможно, вопрос так прост ...

Существует определение enum:

enum uop_flags_enum {
  FICOMP        = 0x001,  
  FLCOMP        = 0x002,  
  FFCOMP        = 0x004, 
  FMEM          = 0x008, 
  FLOAD         = 0x010, 
  FSTORE        = 0x020, 
  FCTRL         = 0x040, 
  FCALL         = 0x080,  
  FRET          = 0x100, 
  FCOND         = 0x200  
};

Где-то в коде есть:

if (uop->flags & FCTRL)

это условие верно, а когда нет?

Ответы [ 6 ]

14 голосов
/ 20 октября 2011

В конечном счете, этот код проверяет, включен ли в переменной uop->flags один бит (флаг FCTRL).

Но вот некоторые объяснения:

Неявно, код if(X) проверяет, является ли X истинным значением.Для целых чисел 0 - единственное «ложное» значение, а все остальное - «истина».

Поэтому ваш код эквивалентен:

if (0 != (uop->flags & FCTRL))

Теперь, чтоэто означает?

Оператор & выполняет "побитовое И", что означает, что каждый бит левой части равен И с соответствующим битом на правой стороне.

Так что, если мы записали два наших операнда в двоичном виде:

uop->flags      1010 1010  (example)

FCTRL           0100 0000

В этом примере, если вы выполните «И» для каждой пары битов, вы получите результат:

result          0000 0000

, который оценивается как ложное, и действительно в этом примере значение uop->flags не имеет установленного флага FCTRL.

Теперь вот еще один пример, где установлен флаг :

uop->flags      1110 1010  (example)

FCTRL           0100 0000

Соответствующий результат ANDed:

result          0100 0000

Этот результат не равен нулю, поэтому "true", вызывая оператор if.

5 голосов
/ 20 октября 2011

Это перечисление, используемое для определения количества «флагов» для операции. Это можно сделать по тому факту, что каждое определенное значение является точной степенью двойки, и поэтому оно представлено одним битом («флагом») значения.

Преимущество этого типа перечисления в том, что вы можете комбинировать столько флагов, сколько хотите, используя побитовое ИЛИ :

uop->flags = FMEM | FLOAD | FRET; // sets the three corresponding flags

Условие, которое вы задаете, которое использует поразрядно И

uop->flags & FCTRL

имеет значение true тогда и только тогда, когда установлен флаг FCTRL, т.е. когда установлен 7-й бит uop->flags. Это потому, что FCTRL == 0x040 == двоичный 01000000.

1 голос
/ 20 октября 2011

Когда бит, соответствующий FCTRL (0x040), установлен в uop-> flags, условие истинно. '&' - это побитовое И, по сути, маскирующее все биты, кроме тех, которые установлены FCTRL.

0 голосов
/ 20 октября 2011

В этом случае каждый следующий элемент перечисления сдвигается на 1 бит влево, поэтому можно проверить, установлен ли какой-либо флаг, просто проверив, если variable & flag == true. Однако что, если мы хотим установить шаблон многобитового флага? Например -

enum {
     #ifdef __GNUC__ // cool in GCC we can use binary constants
        myFlag = 0b1010
     #else           // otherwise fallback into integral constant mode
        myFlag = 10
     #endif
}

когда, как проверить, установлен ли этот параметр в нашей переменной X? Мы не можем просто сделать X & myFlag == true, потому что, например, 0b1000 & myFlag == true и 0b0010 & myFlag == true - но ни в 0b1000, ни в 0b0010 не установлены наши ДВА бита! По этой причине я предпочитаю полную проверку битовой маски, которая позволяет определять многобитовые шаблоны в enum:

#define IS_BIT_MASK_SET(variable,flag) ((variable & flag) == flag)

НТН!

0 голосов
/ 20 октября 2011

Поскольку тип перечисления использует позицию двоичных цифр (то есть, единиц, 2, 4, 8, 16 и т. Д.), А операция выполняет логику и. Если это место бит установлено, значение не будет равно нулю (true), в противном случае оно будет равно false.

0 голосов
/ 20 октября 2011

Условие истинно, когда бит установлен.0x40 - это 1000000, поэтому, когда установлен 7-й бит в flags - это будет истина.

...