C语言 为什么对 C 枚举定义中的值使用 Bitwise-Shift 运算符?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3999922/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 06:46:45  来源:igfitidea点击:

Why use the Bitwise-Shift operator for values in a C enum definition?

cenumsbitwise-operatorsbit-shift

提问by Dave Gallagher

Apple sometimes uses the Bitwise-Shift operator in their enumdefinitions. For example, in the CGDirectDisplay.hfile which is part of Core Graphics:

Apple 有时会在其枚举定义中使用 Bitwise-Shift 运算符。例如,在作为Core Graphics 一部分的CGDirectDisplay.h文件中:

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;

Why not simply use incrementing int's like in a "normal" enum?

为什么不简单地在“普通”枚举中使用递增int

回答by pmg

Maybe writing the values in hexadecimal (or binary) helps :-)

也许以十六进制(或二进制)写入值有帮助:-)

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

Now you can add them (or "or" them) and get different values

现在您可以添加它们(或“或”它们)并获得不同的值

kCGDisplayAddFlag | kCGDisplayDisabledFlag /* 0b0000001000010000 */

回答by sepp2k

This way you can add multiple flags together to create a "set" of flags and can then use &to find out whether any given flag is in such a set.

通过这种方式,您可以将多个标志添加在一起以创建一组“标志”,然后可以&用来找出任何给定的标志是否在这样的集合中。

You couldn't do that if it simply used incrementing numbers.

如果它只是使用递增数字,则无法做到这一点。

Example:

例子:

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

回答by Florian

If you have FlagA=1, FlagB=2 and FlagC=3, FlagA or FlagB would give the same value as FlagC. The shift operator is used to ensure that every combination of flags is unique.

如果您有 FlagA=1、FlagB=2 和 FlagC=3,FlagA 或 FlagB 将给出与 FlagC 相同的值。移位运算符用于确保每个标志组合都是唯一的。

回答by AustinWBryan

New in C# 7 is finally adding binary literals, so you can just write it as this:

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

And if you want to make things even neater, you use this: _which is also new to C# 7, which allows you to put spaces in numbers to make things more readable, like so:

如果你想让事情更整洁,你可以使用这个:_这也是 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;
};

Makes it so much easier to keep track of the numbers.

使跟踪数字变得如此容易。

回答by Vladimir

This will allow for a variable to easily combine multiple flags:

这将允许变量轻松组合多个标志:

unit32_t multFlag = kCGDisplayRemoveFlag | kCGDisplayMirrorFlag | kCGDisplaySetMainFlag'

回答by Jayhello

Let's me give you a more practice example. In c++ when you want to open a file (Open for output, and in binary mode opposed to text mode), you can do it by:

让我给你一个更实际的例子。在 C++ 中,当你想打开一个文件(打开输出,以二进制模式与文本模式相反)时,你可以这样做:

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

You can see, ios::out | ios::binarycan set two mode(Open for output, and in binary mode).

可以看到,ios::out | ios::binary可以设置两种模式(打开输出,和二进制模式)。

How does this work ? It's by enum(bitwise-shift values):

这是如何运作的 ?它是通过枚举(按位移位值):

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;

If you use value increment by 1 in enum _Ios_Openmode, you have to set(ios::out)and set(ios::binary)do two times. It may not so convenient to check and set value by one time.

如果您在使用值递增1 enum _Ios_Openmode,你要set(ios::out)set(ios::binary)做两次。一次检查和设置值可能不太方便。

回答by N 1.1

.. because 1<<7looks more concise and easier to read than 01000000. Doesn't it?

.. 因为1<<7看起来比..更简洁,更容易阅读01000000。不是吗?

回答by richard

using #define is more understandable. but enum could group these value togater.

使用#define 更容易理解。但枚举可以将这些值分组。