开发者

Bitwise, bitmasking: whats wrong here?

I wanted to track some options via bitmask'ing them, and borrowed bitmask values from this answer,开发者_如何转开发 yet they not seem to work together.

#include <iostream>

#define OP1 0x00003FFFUL
#define OP2 0x00007FFFUL
#define OP3 0x0000FFFFUL

int main() {
        unsigned long params = 0; // .
        params |= OP3;
        if ( (params & OP1) == OP1)
                std::cout << "Whoa. Lame masking\n";
}

Is it a type problem, or this method can't be used for holding more than 1 option at a time (both OP1, OP2 and OP3 are wanted to stay in same params)?


For options you should use other masks, ones that are not overlapped, such as:

   #define OP1 0x000000FUL
   #define OP2 0x00000F0UL
   #define OP3 0x0000F00UL

or (in this case you'll be able to store as many options as available bits):

   #define OP1 0x0000001UL
   #define OP2 0x0000002UL
   #define OP3 0x0000004UL
   //ETC...

Your masks will never work properly because if OP3 is set then OP1 and OP2 will be contained (the same goes if you use OP2, then OP1 will be implied):

     FFFF = 1111111111111111
  &  3FFF = 0011111111111111
     -----------------------
     3FFF = 0011111111111111

The masks in the example you pasted were intended to extrapolate the last bits of an UL.


What do you think is the value of 0xF & 0x3?


It has all 'options'. The problem is, bits in OP1, OP2 and OP3 overlap. OP3 has all bits of OP1 and OP2 also set. so, OP3&OP1 will equal OP1, and OP3&OP2 will equal OP2. Hence, the confusion. This wouldn't be the case if OP1=1, OP2=2, OP3=4. Then you'd also have to set the flag as

params |= OP1 | OP2 | OP3

But if you require OP1, OP2 and OP3 to be what you have provided, then there is no problem with your bitmasking code.


This implementation is probably strange unless you have some other stuff going on that isn't shown (seems unlikely since it is taken from another question). A better solution would likely be to enum out your bitmask. Something like:

enum values {
    aaa = 1 << 0,
    bbb = 1 << 1,
    ccc = 1 << 2,
    ab = aaa | bbb,
    ac = aaa | ccc,
    abc = aaa | bbb | ccc,
    bc = bbb | ccc, };

which can then be used like:

unsigned int var = abc;
if (var & aaa) {
    cout << "OK";
}

which outputs 'OK'

This gives you the overlapping values that you might want while also clearly defining the relationships between them. If you wanted to get fancier yet you can do:

namespace blah {
enum values {
    aaa = 1 << 0,
    bbb = 1 << 1,
    ccc = 1 << 2,
    ab = aaa | bbb,
    ac = aaa | ccc,
    abc = aaa | bbb | ccc,
    bc = bbb | ccc,
};
}

This will give you the ability to use it like:

unsigned int var = blah::abc;
if (var & blah::aaa) {
    cout << "OK";
}

Which again outputs 'OK'

Which becomes nice if you are using the full width of a uint and many combinations of the flags (it doesn't clutter up your main namespace).


You are not initialising params.

Try:

unsigned long params = 0;

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜