简体   繁体   English

使用按位运算符了解枚举成员的初始化

[英]Understanding enum members' initialization with bitewise operators

I'm currently reading the "SFML game development" book and in Chapter 4 - Input Handling in the sub-chapter "Receiver Category", paragraph n°2; 我目前正在阅读《 SFML游戏开发》这本书,并在“接收机类别”子章节的第4章“输入处理”中,第2段; we've got this: 我们有这个:

"We define an enum to refer to the different categories. Each category except None is initialized with an integer that has one bit set to 1 , and the rest are set to 0 :" “我们定义一个枚举来引用不同的类别。除None以外的每个类别都用一个整数初始化,该整数的一位设置为1,其余位设置为0:”


namespace Category
{
   enum Type
   {
     None = 0,
     Scene = 1 << 0,
     PlayerAircraft = 1 << 1,
     AlliedAircraft = 1 << 2
     EnemyAircraft = 1 << 3,
   };
}

I'm not really comfortable with bitwise operators and binary operations in general; 一般来说,我对按位运算符和二进制运算并不满意。 so I don't understand that part "Each category except None is initialized with an integer that has one bit set to 1 , and the rest are set to 0 :". 所以我不明白那部分“除None之外的每个类别都用一个整数设置,该整数的一位设置为1,其余设置为0:”。

If each category (except None) is initialized as said above, what is "the rest" set to 0 ?! 如果如上所述对每个类别(无除外)进行了初始化,那么“其余”设置为0是什么?!

Note : After double-reading I think I understand that each member of the enum is a byte and so, the first bit of those is set to 1 and the other bits of the same byte are set to 0. So, Scene = 0b1, PlayerAircraft = 0b10 (one bit = 1, the other = 0), etc... so if I would have write : PlayerAircraft = 2 << 1 PlayerAircraft would have been equal to 0b11? 注意 :经过双重阅读后,我认为我了解到枚举的每个成员都是一个字节,因此,将它们的第一位设置为1,并将同一字节的其他位设置为0。因此,Scene = 0b1, PlayerAircraft = 0b10(一个位= 1,另一个= 0),依此PlayerAircraft = 2 << 1 ...因此,如果我要写: PlayerAircraft = 2 << 1 PlayerAircraft等于0b11吗? am I right or I'm missing something? 我是对的还是我错过了什么?

Further in the chapter; 在本章的后面; we've got a if condition checking if the requested category is the same as the scene node one; 我们进行了if条件检查,检查所请求的类别是否与场景节点一相同; without going off-subject; 不脱离主题 I didn't understand that part. 我不明白那部分。 Since it uses a AND (or & if you prefer) bitwise operator; 由于它使用AND (或&如果您愿意的话)按位运算符; how could it check if the scene node category is the same as the requested one? 如何检查场景节点类别是否与请求的节点类别相同? I've check on Wikipedia how it works but I didn't fully get it. 我已经在Wikipedia上查看了它的工作原理,但是我没有完全了解它。

Here's the code 这是代码

void SceneNode::onCommand(const Command& command, sf::Time dt)
{
   if(command.category & getCategory()) //The part I don't understand
     command.action(*this, dt);
/* ... */
}

I don't get it... 我不明白...

Voilà, thank you in advance and I hope my first post in here isn't too messy and that I have provided enough informations. Voilà,在此先感谢您,我希望我在这里的第一篇文章不会太乱,我已经提供了足够的信息。 If not, I will edit! 如果没有,我将编辑! :) :)

PS: Sorry for the lame English, I'm not awake enough today. PS:对不起,英语不好,我今天还不够清醒。

What's operator<< ? 什么是operator<<

Understanding operator<< , in this case, is very easy. 在这种情况下,了解operator<<非常容易。 What's on the left of the operator is the current value object; 运算符左侧是当前值对象。 what's on the right is how many left shifts we should perform. 右边是我们应该执行多少次左移。

So for example, given a byte corresponding to 1 : 因此,例如,给定一个对应于1的字节:

0 0 0 0 0 0 0 1

a single shift to left would lead to: 向左单移将导致:

0 0 0 0 0 0 1 0

Now, if we think of 1 as 2 ^ 0 , at every left shift we are incrementing the exponent. 现在,如果我们将1视为2 ^ 0 ,则在每个左移位置我们都在增加指数。 Therefore the above byte is equal to 2 ^ 1 and so on: 因此,上述字节等于2 ^ 1 ,依此类推:

0 0 0 0 0 0 0 1 // 2 ^ 0 = 1
0 0 0 0 0 0 1 0 // 2 ^ 1 = 2
0 0 0 0 0 1 0 0 // 2 ^ 2 = 4
0 0 0 0 1 0 0 0 // 2 ^ 3 = 8
...

What's operator& ? 什么是operator&

The binary operator& is the bitwise AND. 二进制 operator&是按位与。 For each corresponding bit of two bit sets, the resulting bit is 1 if both bits are 1 , 0 otherwise. 对于两个位组各对应位的,所得到的位为1 ,如果两个位都为10否则。 You can use it to check if, in a given bitset, a specific category is present. 您可以使用它来检查在给定的位集中是否存在特定类别。 For example, let's consider category: 例如,让我们考虑类别:

0 0 0 0 0 1 0 0

and let's consider a bitset that represents category 1 and 2, but not our category 3: 让我们考虑一个代表类别1和2的位集,而不是代表类别3的位集:

0 0 0 0 0 0 1 1

The bitwise AND between the two would give 0 (which is implicitly convertible to false ): 两者之间的按位与将为0 (可以隐式转换为false ):

0 0 0 0 0 1 0 0 &
0 0 0 0 0 0 1 1 =
0 0 0 0 0 0 0 0

On the other hand, if our bit set (now representing the first and third category) contained our category: 另一方面,如果我们的位集(现在代表第一和第三类别)包含我们的类别:

0 0 0 0 0 1 0 0 &
0 0 0 0 0 1 0 1 =
0 0 0 0 0 1 0 0

you would have a bitset representing a bit different from 0 (and therefore implicitly convertible to true ). 您将拥有一个表示不同于0的位集(因此隐式转换为true )。

Conclusion 结论

If you represent every category as a single bit in a bit set, you can easily represent a group of categories in a single bit set. 如果将每个类别表示为一个位集中的单个位,则可以轻松地将一组类别表示为一个位集中。

Let's say that we want to represent the four letters A , C , G , T . 假设我们要代表四个字母ACGT We could assign a single bit in a bit set of length four: 我们可以在长度为四的位集中分配一位:

0 0 0 1 // A
0 0 1 0 // C
0 1 0 0 // G
1 0 0 0 // T

Now let's forge a bitset that represents letters A and G : 现在让我们伪造一个代表字母AG

0 1 0 1 // A + G

We can check if a given letter is in the bit set via & . 我们可以通过&来检查给定字母是否在设置的位中。

Is there an A ? A吗?

0 1 0 1 & // A + G
0 0 0 1 = // A
0 0 0 1   // 1 ~ true

Yes, there is. 就在这里。 Is there a C ? C吗?

0 1 0 1 & // A + G
0 0 1 0 = // C
0 0 0 0   // 0 ~ false

Nope. 不。 Is there a G ? G吗?

0 1 0 1 & // A + G
0 1 0 0 = // G
0 1 0 0   // 4 ~ true

Yes, there's. 是的,有。 And finally, is there a T ? 最后,有T吗?

0 1 0 1 & // A + G
1 0 0 0 = // T
0 0 0 0   // 0 ~ false

No, there's not. 不,没有。

In general 一般来说

Generally speaking, given a bit set a and the bit set b for the category we want to check for existence in a , the result of & can only be of two kinds: 一般来说,给定一个位设置a和位组b因为我们想在检查存在的类别a ,结果&只能分为两种类型:

  1. 0
  2. the value assigned to the category (a power of two) 分配给类别的值(2的幂)

In C++, testing for: 在C ++中,测试以下各项:

if (a & b)

can also be specified as: 也可以指定为:

if ((a & b) == a)

Practical example 实际例子

Now you should be able to understand that given an enum like: 现在您应该能够理解给定的enum例如:

enum type
    { none              = 0
    , scene             = 1 << 0
    , player_aircraft   = 1 << 1
    , allied_aircraft   = 1 << 2
    , enemy_aircraft    = 1 << 3 };

and these variables: 和这些变量:

auto a = scene;
auto b = enemy_aircraft;
auto c = player_aircraft;

the following: 下列:

    std::cout << "a is of type: " << ((a & scene) ? "scene" : "not scene") << '\n';    
    std::cout << "b is of type: " << ((b & enemy_aircraft) ? "enemy_aircraft" : "not enemy_aircraft") << '\n'; 
    std::cout << "c is of type: " << ((c & player_aircraft) ? "player_aircraft" : "not player_aircraft") << '\n'; 

will print: 将打印:

a is of type: scene a是类型:场景

b is of type: enemy_aircraft b的类型:敌人飞机

c is of type: player_aircraft c类型:player_aircraft

Live demo 现场演示

The << operator performs left shift operation. <<操作符执行左移操作。 Examples: 例子:

1 << 0 ( 00000001 in binary) 1 << 0 (二进制00000001

1 << 1 ( 00000010 in binary) 1 << 1 (二进制00000010

1 << 2 ( 00000100 in binary) 1 << 2 (二进制00000100

so if I would have write : PlayerAircraft = 2 << 1 PlayerAircraft would have been equal to 0b11? 所以如果我要写:PlayerAircraft = 2 << 1 PlayerAircraft等于0b11吗? am I right or I'm missing something? 我是对的还是我错过了什么?

2 is 00000010 in binary so 2 << 1 is 4 ( 00000100 in binary). 2是二进制的00000010 ,所以2 << 14 (二进制的00000100 )。

& is the bitwise operator AND. &是按位运算符AND。 The result of its applaying is equal to 1 if both bits (the left and the right operands of the operator) are also equal to 1. Otherwise the result is 0. 如果两个位(运算符的左操作数和右操作数)也都等于1,则其施加的结果等于1。否则,结果为0。

Let assume for example that sf::Time dt has value AlliedAircraft defined as AlliedAircraft = 1 << 2 that is equivalent to binary literal 0b100 . 例如,假设sf::Time dtAlliedAircraft定义为AlliedAircraft = 1 << 2 ,它等效于二进制文字0b100 So if command.category is also contains AlliedAircraft then the result of the operator & will be the same value 0b100 因此,如果command.category也包含AlliedAircraft则运算符&的结果将为相同的值0b100

0b100
&
0b100
=====
0b100

So as 0b100 is not equal to zero then the condition in the if statement will be equal to true . 因此,由于0b100不等于零,因此if语句中的条件将等于true

Let's assume that command.category contains for example PlayerAircraft that defined as PlayerAircraft = 1 << 1 that in turn is equivalent to binary literal 0b010 In this case we will get 让我们假设command.category包含例如PlayerAircraft是定义为PlayerAircraft = 1 << 1 ,这又相当于二进制文字0b010在这种情况下,我们会得到

0b010
&
0b100
=====
0b000

The result value will be equal to zero and the corresponding condition will be equal to false . 结果值将等于零,并且相应的条件将等于false

This is not really initialisation - the enumeration item are compile time constants, and the bitwise expressions are evaluated at compile time. 这并不是真正的初始化 -枚举项是编译时常量,并且在编译时对按位表达式进行求值。

The binary representation of each member will be: 每个成员的二进制表示形式为:

 None           : 00000000
 Scene          : 00000001
 PlayerAircraft : 00000010
 AlliedAircraft : 00000100
 EnemyAircraft  : 00001000

Though the actual number of bits will be larger - I have shown only the least significant 8 bits the rest will be zero. 尽管实际位数会更大-我只显示了最低有效的8位,其余则为零。

Enumerations of this type might be used when a value may simultaneously represent multiple values - for example the combination of PlayerAircraft | Scene 当一个值可以同时表示多个值时,可以使用这种类型的枚举-例如PlayerAircraft | Scene PlayerAircraft | Scene has a unique value 00000011; PlayerAircraft | Scene具有唯一值00000011; though not that PlayerAircraft | Scene 虽然不是那个PlayerAircraft | Scene PlayerAircraft | Scene has type int rather than Type , and it is not clear in this case that this is the purpose of the bit masks. PlayerAircraft | Scene具有类型int而不是Type ,并且在这种情况下尚不清楚这是否是位掩码的目的。

The use of the bit shift constant expression is probably merely to make it clear that a single bit is being set for each enumeration. 使用位移常数表达式可能只是为了清楚地表明每个枚举都设置了一个位。 You might just as well write: 您可能会这样写道:

 None           = 0x00,
 Scene          = 0x01,
 PlayerAircraft = 0x02,
 AlliedAircraft = 0x04,
 EnemyAircraft  : 0x08

Hexadecimal notation is often used because it is a succinct notation for binary values as one digit corresponds exactly to 4 binary digits. 十六进制表示法经常使用,因为它是二进制值的简洁表示法,因为一位数字正好对应于4个二进制数字。

To test whether an individual bit in a binary value is set, you bitwise-& the value with the mask you want to test for. 要测试是否设置了二进制值中的单个位,请将该值与要测试的掩码按位进行“与”运算。 For example: 例如:

value      : 1001
Scene Mask : 0001
-----------------
         & : 0000  // Non-zero - value Scene bit is set


value       : 1001
Player Mask : 0010
------------------
          & : 0000  // Zero - Value Palyer bit is not set

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM