0

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)?

Community
  • 1
  • 1
kagali-san
  • 2,964
  • 7
  • 48
  • 87
  • 1
    What were you intending to do? Now it sets the last 16 bits, then tests if the last 14 bits are set. They are, so it prints "Whoa. Lame masking", which is the correct behavior after those actions. – jjrv Jun 05 '11 at 20:21
  • @Henk Holtermann, smart initialization. `= 0` does no effect. – kagali-san Jun 05 '11 at 20:21
  • All bits of OP1 are also set in OP3, the `&` selects them out. I would expect true. – H H Jun 05 '11 at 20:24
  • 1
    Try other masks, such as 0x1, 0x2 and 0x4. – Omri Barel Jun 05 '11 at 20:26
  • What does the `UL` mean in your numbers? – Midas Jun 05 '11 at 20:30
  • 1
    You're doing `0|F&3` which in binary is `0000|1111&0011=1111&0011=0011`, so, why are you surprised? – trutheality Jun 05 '11 at 20:30
  • @trutheality: What is the use of that? – Midas Jun 05 '11 at 20:31
  • 1
    @Midas: in C and C++, whenever you write integer numbers in your code they're assumed to be `int`s. Other types have to be specified by appending letters like `U` and `L`. – trutheality Jun 05 '11 at 20:34
  • 1
    @mhambra: That is not true at all. Without the initialization, the variable has an indeterminate value, and later using it is undefined. – Lightness Races in Orbit Jun 05 '11 at 20:42
  • @Tomalak: actually most compilers set uninitialized variables to 0. – trutheality Jun 05 '11 at 20:48
  • @trutheality: I don't care. The C++ Standard has very specific rules about when primitives are and are not initialised. It's unusual to see them contravened (so I'd love to get a citation on that "most compilers" assertion) and relying on the completely opposite is a terrible idea. (And, actually, you're referring to the behaviour of some runtimes that pre-zero stack memory.) – Lightness Races in Orbit Jun 05 '11 at 22:23
  • @Tomalak: I'll agree with that. I might be wrong about the compilers vs. runtimes thing. – trutheality Jun 05 '11 at 22:26

5 Answers5

4

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.

Federico Vera
  • 1,357
  • 1
  • 12
  • 18
2

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

Andrei
  • 4,880
  • 23
  • 30
2

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.

Raze
  • 2,175
  • 14
  • 30
2

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).

ddeflyer
  • 96
  • 5
  • 1
    Forgot to say that you can still do |= using these values and you don't have to specify all combinations, only the ones that make sense together and that you are going to use. – ddeflyer Jun 05 '11 at 21:10
1

You are not initialising params.

Try:

unsigned long params = 0;

Omri Barel
  • 9,182
  • 3
  • 29
  • 22
  • Actually I have to agree with jjrv. No idea what you were trying to do. The masks aren't exclusive, so when you or with OP3 you are getting OP1 and OP2 at the same time. – Omri Barel Jun 05 '11 at 20:23