Checking if a bit is set, when it's not the first

Started by
8 comments, last by ongamex92 8 years, 6 months ago

If I had:

00010101

And I wanted to check if the third bit, the one between the other 2 positive ones is positive, should I do a shift to the right, so it becomes the right most 1 bit, then do a shift to the left, so it becomes the left most 1 bit? Then shift, AGAIN, so it goes back to its original position, so i can use & on it?

>> 00000101

<< 10000000

>> 00000100

What im actually asking is: when the bit you want to check, is between other bits, should I handle it this way?

Advertisement

bool is_set(uint x, uint bit)
{
  return ((x >> bit) & 0x01);
}

Think thats right :)


bool is_set(uint x, uint bit)
{
  return ((x >> bit) & 0x01);
}

Think thats right smile.png

Yeah, that makes a hell of a lot more sense than my logic. Thank you

Alternatively:


return x & (1 << bit);

Which works by masking everything but that bit and checking if the result is nonzero.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

http://www.gamedevpensieve.com/programming/language/c/bitwise-operation

@spinningcubes | Blog: Spinningcubes.com | Gamedev notes: GameDev Pensieve | Spinningcubes on Youtube

Alternatively:

return x & (1 << bit);
Which works by masking everything but that bit and checking if the result is nonzero.


Be careful with the exact types involved. If x is a 64-bit type and you have 32-bit ints, checking bit 40 won't work well with that code, but it'll be fine with the `(x >> bit) & 1' version.

EDIT: Even if x is an unsigned 32-bit integer, I believe checking bit 31 with that code was technically undefined behavior (because of overflow) until C++14.

Alternatively:


return x & (1 << bit);

Which works by masking everything but that bit and checking if the result is nonzero.

I always explicitly compare such expressions against 0 to denote it's a test result rather than a numeric answer:


return (x & (1 << bit)) != 0;

Alternatively:


return x & (1 << bit);
Which works by masking everything but that bit and checking if the result is nonzero.

Be careful with the exact types involved. If x is a 64-bit type and you have 32-bit ints, checking bit 40 won't work well with that code, but it'll be fine with the `(x >> bit) & 1' version.
EDIT: Even if x is an unsigned 32-bit integer, I believe checking bit 31 with that code was technically undefined behavior (because of overflow) until C++14.

I've been stung by that 64-bit bug before... sad.png
Upgraded a bunch of types from uint32's to uint64's to pack more fields into my masks, and suddenly half my bitmasks stop working sad.png needed (1ULL << index), (((uint64)1) << index), etc, instead of (1 << index).

On the same topic as edit - right shift is also bullshit (aka "implementation defined") in C++ too. Although I've never used a compiler that doesn't treat right-shift of a signed variable to be arithmetic/sign-extending, and a right-shift of an unsigned variable to be logical/zero-fill.

On the same topic as edit - right shift is also bullshit (aka "implementation defined") in C++ too. Although I've never used a compiler that doesn't treat right-shift of a signed variable to be arithmetic/sign-extending, and a right-shift of an unsigned variable to be logical/zero-fill.


I have develop two habits that save me a lot of grief:
(1) always use unsigned integer types when doing bitwise manipulations (all these operations are well defined for unsigned types), and
(2) always use literals of the correct type (so 1u if it's an unsigned int, 1ull if it's an unsigned long long, 1.0 if it's a double, etc.).

BTW for masks and Booleans at work we just define a bit-field structure, with an int cast operator if we really need an integer mask.

This topic is closed to new replies.

Advertisement