Зачем использовать оператор Bitwise-Shift для значений в определении C enum? - PullRequest
35 голосов
/ 22 октября 2010

Apple иногда использует оператор Bitwise-Shift в своих определениях enum . Например, в файле CGDirectDisplay.h , который является частью Core Graphics:

enum {
  kCGDisplayBeginConfigurationFlag  = (1 << 0),
  kCGDisplayMovedFlag           = (1 << 1),
  kCGDisplaySetMainFlag         = (1 << 2),
  kCGDisplaySetModeFlag         = (1 << 3),
  kCGDisplayAddFlag         = (1 << 4),
  kCGDisplayRemoveFlag          = (1 << 5),
  kCGDisplayEnabledFlag         = (1 << 8),
  kCGDisplayDisabledFlag        = (1 << 9),
  kCGDisplayMirrorFlag          = (1 << 10),
  kCGDisplayUnMirrorFlag        = (1 << 11),
  kCGDisplayDesktopShapeChangedFlag = (1 << 12)
};
typedef uint32_t CGDisplayChangeSummaryFlags;

Почему бы просто не использовать приращения int как в "обычном" enum ?

Ответы [ 8 ]

74 голосов
/ 22 октября 2010

Может быть, поможет запись значений в шестнадцатеричном (или двоичном) виде: -)

enum {
  kCGDisplayBeginConfigurationFlag  = (1 << 0), /* 0b0000000000000001 */
  kCGDisplayMovedFlag               = (1 << 1), /* 0b0000000000000010 */
  kCGDisplaySetMainFlag             = (1 << 2), /* 0b0000000000000100 */
  kCGDisplaySetModeFlag             = (1 << 3), /* 0b0000000000001000 */
  kCGDisplayAddFlag                 = (1 << 4), /* 0b0000000000010000 */
  kCGDisplayRemoveFlag              = (1 << 5), /* 0b0000000000100000 */
  kCGDisplayEnabledFlag             = (1 << 8), /* 0b0000000100000000 */
  kCGDisplayDisabledFlag            = (1 << 9), /* 0b0000001000000000 */
  kCGDisplayMirrorFlag              = (1 << 10),/* 0b0000010000000000 */
  kCGDisplayUnMirrorFlag            = (1 << 11),/* 0b0000100000000000 */
  kCGDisplayDesktopShapeChangedFlag = (1 << 12) /* 0b0001000000000000 */
};

Теперь вы можете добавить их (или "или") и получить другие значения

kCGDisplayAddFlag | kCGDisplayDisabledFlag /* 0b0000001000010000 */
55 голосов
/ 22 октября 2010

Таким образом, вы можете добавить несколько флагов вместе, чтобы создать «набор» флагов, и затем можете использовать &, чтобы узнать, есть ли какой-либо данный флаг в таком наборе.

Вы не могли сделатьчто если он просто использовал увеличивающиеся числа.

Пример:

int flags = kCGDisplayMovedFlag | kCGDisplaySetMainFlag; // 6
if(flags & kCGDisplayMovedFlag) {} // true
if(flags & kCGDisplaySetModeFlag) {} // not true
4 голосов
/ 22 октября 2010

Если у вас есть FlagA = 1, FlagB = 2 и FlagC = 3, FlagA или FlagB дадут то же значение, что и FlagC.Оператор сдвига используется для обеспечения уникальности каждой комбинации флагов.

2 голосов
/ 15 мая 2018

Новое в C # 7, наконец, добавляет двоичные литералы, так что вы можете просто написать это так:

enum MyEnum
{
    kCGDisplayBeginConfigurationFlag  = 0b0000000000000001;
    kCGDisplayMovedFlag               = 0b0000000000000010;
    kCGDisplaySetMainFlag             = 0b0000000000000100;
    kCGDisplaySetModeFlag             = 0b0000000000001000;
    kCGDisplayAddFlag                 = 0b0000000000010000;
    kCGDisplayRemoveFlag              = 0b0000000000100000;
    kCGDisplayEnabledFlag             = 0b0000000001000000;
    kCGDisplayDisabledFlag            = 0b0000000010000000;
    kCGDisplayMirrorFlag              = 0b0000000100000000;
    kCGDisplayUnMirrorFlag            = 0b0000001000000000;
    kCGDisplayDesktopShapeChangedFlag = 0b0000010000000000;
};

И если вы хотите сделать вещи еще аккуратнее, вы используете это: _, который также является новым для C # 7, который позволяет вам ставить пробелы в числах, чтобы сделать вещи более читабельными, например:

enum MyEnum
{
    kCGDisplayBeginConfigurationFlag  = 0b_0000_0000_0000_0001;
    kCGDisplayMovedFlag               = 0b_0000_0000_0000_0010;
    kCGDisplaySetMainFlag             = 0b_0000_0000_0000_0100;
    kCGDisplaySetModeFlag             = 0b_0000_0000_0000_1000;
    kCGDisplayAddFlag                 = 0b_0000_0000_0001_0000;
    kCGDisplayRemoveFlag              = 0b_0000_0000_0010_0000;
    kCGDisplayEnabledFlag             = 0b_0000_0000_0100_0000;
    kCGDisplayDisabledFlag            = 0b_0000_0000_1000_0000;
    kCGDisplayMirrorFlag              = 0b_0000_0001_0000_0000;
    kCGDisplayUnMirrorFlag            = 0b_0000_0010_0000_0000;
    kCGDisplayDesktopShapeChangedFlag = 0b_0000_0100_0000_0000;
};

Упрощает отслеживание чисел.

2 голосов
/ 22 октября 2010

Это позволит переменной легко комбинировать несколько флагов:

unit32_t multFlag = kCGDisplayRemoveFlag | kCGDisplayMirrorFlag | kCGDisplaySetMainFlag'
0 голосов
/ 20 сентября 2018

Позвольте мне привести вам более практический пример.В C ++, когда вы хотите открыть файл (открыть для вывода, и в двоичном режиме, а не в текстовом режиме), вы можете сделать это следующим образом:(Открыть для вывода и в двоичном режиме).

Как это работает?Это по enum (значения по битам):

enum _Ios_Openmode 
{ 
  _S_app        = 1L << 0,
  _S_ate        = 1L << 1,
  _S_bin        = 1L << 2,  /* 0b0000000000000100 */
  _S_in         = 1L << 3,
  _S_out        = 1L << 4,  /* 0b0000000000010000 */
  _S_trunc      = 1L << 5
  //.....
};

/// Perform input and output in binary mode (as opposed to text mode).
static const openmode binary =  _S_bin;

/// Open for input.  Default for @c ifstream and fstream.
static const openmode in =      _S_in;

/// Open for output.  Default for @c ofstream and fstream.
static const openmode out =     _S_out;

Если вы используете приращение значения на 1 в enum _Ios_Openmode, вам придется set(ios::out) и set(ios::binary) сделать два раза,Возможно, не очень удобно проверять и устанавливать значение за один раз.

0 голосов
/ 23 октября 2010

использование #define более понятно.но enum может сгруппировать эти значения togater.

0 голосов
/ 22 октября 2010

.. потому что 1<<7 выглядит более лаконично и легче для чтения, чем 01000000.Не так ли?

...