Warum den Bitwise-Shift-Operator für Werte in einer C-Enum-Definition verwenden?

Lesezeit: 1 Minute

Apple verwendet manchmal den Bitwise-Shift-Operator in ihren Aufzählung Definitionen. Zum Beispiel im CGDirectDisplay.h Datei, die Teil von Core Graphics ist:

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;

Warum nicht einfach inkrementieren intist wie in einem “normalen” Aufzählung?

  • Verwandte Frage: stackoverflow.com/questions/2159138/…

    – Oded

    22. Oktober 2010 um 18:48 Uhr

  • Es ist leicht zu erkennen, dass die Aufzählung alle Flags mit nur einem einzigen gesetzten Bit sind.

    – Martin York

    22. Oktober 2010 um 19:26 Uhr


  • Eigentlich ist der wahre Grund, wie Loki betonte, die Lesbarkeit. Sie könnten 1, 2, 4, 8, 16 usw. verwenden (Potenzen von 2), aber Sie laufen Gefahr, Fehler zu machen, während 1 << 0, 1 << 1, 1 << 2, 1 << 3 einfacher ist einzutippen und zu lesen, während es dem Compiler überlassen wird, die tatsächlichen Werte zu berechnen. Wenn Sie intelligent programmieren möchten, müssen Sie wissen, was der Compiler für Sie tun kann, und seine Fähigkeiten nutzen.

    – Telemat

    29. Juni 2014 um 4:06 Uhr

Vielleicht hilft es, die Werte hexadezimal (oder binär) zu schreiben 🙂

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 */
};

Jetzt können Sie sie hinzufügen (oder “oder” sie) und andere Werte erhalten

kCGDisplayAddFlag | kCGDisplayDisabledFlag /* 0b0000001000010000 */

  • SO klar, Sie könnten dies als akzeptierte Antwort festlegen.

    – Urkunde02392

    27. September 2013 um 0:31 Uhr

  • Welche Einschränkungen wären damit verbunden? Gibt es ein Maximum von, sagen wir, 16 Werten, die Sie in diese Aufzählung einfügen können, bevor Ihnen die Möglichkeiten ausgehen?

    – meine Anmeldung

    15. Februar 2017 um 13:10 Uhr

  • @mylogon: Es ist implementierungsabhängig. C11 garantiertunsigned int kann 16 Bit halten, unsigned long kann mindestens 32 Bit aufnehmen.

    – pmg

    15. Februar 2017 um 17:44 Uhr


Auf diese Weise können Sie mehrere Flaggen zusammenfügen, um einen “Satz” von Flaggen zu erstellen und diese dann zu verwenden & um herauszufinden, ob sich ein bestimmtes Flag in einem solchen Satz befindet.

Sie könnten das nicht tun, wenn es einfach aufsteigende Zahlen verwenden würde.

Beispiel:

int flags = kCGDisplayMovedFlag | kCGDisplaySetMainFlag; // 6
if(flags & kCGDisplayMovedFlag) {} // true
if(flags & kCGDisplaySetModeFlag) {} // not true

  • Nun, das erklärt ein paar Dinge für C++-Code, bei dessen Entwirrung ich helfe. Vielen Dank!

    – CodeMouse92

    3. Februar 2015 um 2:29 Uhr

Benutzeravatar von AustinWBryan
AustinWBryan

Neu in C# 7 ist endlich das Hinzufügen von Binärliteralen, sodass Sie es einfach so schreiben können:

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

Und wenn Sie es noch ordentlicher machen wollen, verwenden Sie dies: _ Das ist auch neu in C # 7, mit dem Sie Leerzeichen in Zahlen einfügen können, um die Lesbarkeit zu verbessern, wie folgt:

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;
};

Macht es so viel einfacher, den Überblick über die Zahlen zu behalten.

  • Ich wollte sicherstellen, dass das, was ich tun wollte, in C legitim ist. In diesem Thread geht es speziell um Aufzählungen und bitweise Operatoren in C. Es scheint viele andere Threads zu Aufzählungen und bitweisen Operationen speziell für C# zu geben. Ich bin mir nicht sicher, ob ich Details zu C# hinzufüge Dies Faden ist hilfreich.

    – CarlRJ

    28. Oktober 2019 um 20:21 Uhr


Benutzeravatar von Florian
Florian

Wenn Sie FlagA=1, FlagB=2 und FlagC=3 haben, würde FlagA oder FlagB den gleichen Wert wie FlagC ergeben. Der Verschiebungsoperator wird verwendet, um sicherzustellen, dass jede Kombination von Flags eindeutig ist.

Dadurch kann eine Variable problemlos mehrere Flags kombinieren:

unit32_t multFlag = kCGDisplayRemoveFlag | kCGDisplayMirrorFlag | kCGDisplaySetMainFlag'

Benutzeravatar von Jayhello
Jayhallo

Lassen Sie mich Ihnen ein praktischeres Beispiel geben. Wenn Sie in C++ eine Datei öffnen möchten (für die Ausgabe öffnen und im Binärmodus im Gegensatz zum Textmodus), können Sie dies folgendermaßen tun:

const char *filename = "/home/xy/test.bin";
fstream output(filename, ios::out | ios::binary);

Du kannst sehen, ios::out | ios::binary kann zwei Modi einstellen (für Ausgang öffnen und im Binärmodus).

Wie funktioniert das ? Es ist durch Aufzählung (bitweise Verschiebungswerte):

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;

Wenn Sie die Werterhöhung um 1 Zoll verwenden enum _Ios_OpenmodeSie müssen set(ios::out) und set(ios::binary) zwei mal machen. Es kann nicht so bequem sein, den Wert einmal zu überprüfen und einzustellen.

Benutzeravatar von N 1.1
N 1.1

.. Weil 1<<7 sieht prägnanter und leichter zu lesen als aus 01000000. Nicht wahr?

  • Dies beantwortet die Frage nicht

    – Kunstmann

    14. Dezember 2017 um 14:36 ​​Uhr

1404440cookie-checkWarum den Bitwise-Shift-Operator für Werte in einer C-Enum-Definition verwenden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy