Siemel Naran said:
Old Wolf said:
x |= (1 << n); // set bit n to 1
x &= ~(1 << n); // set bit n to 0
if (x&(1 << n)) // true if bit n is 1
These should probably be 1UL instead of 1, because of the case where
x is [unsigned] 'long' and sizeof(long) > sizeof(int).
Is there a promotion from int -> long in expressions like int<<long? If so,
then we could make either 1 or n into an unsigned long, right?
Nope. There is for '+', '-' etc. but not for the shift operators.
What about the case where x is an enum. Then how do we know what to use for
1 or n? Sometimes unsigned short is appropriate, sometimes unsigned int,
unsigned long, unsigned long long if our compiler supports this. If we had
typeof then we'd just say { x |= (typeof(X)1 << typeof(X)n). Or do we have
to use std::bitset here?
[Note - this discussion applies to the case where the above expressions
are implemented as macros (otherwise , if it's a function or direct
expression, then typeof(x) is known)]
It doesn't matter if the type is too long because the compiler
will optimise it down. Also I wonder if you could get uber-portability
with (((x)&0)+1) instead of just (1), or something. That does introduce
he side-effect of evaluating (x) twice in the testing expression though.
If we are in C++ (as the NG suggests
) then they can just be
implemented as template functions without much difficulty, eg.
template<typename T> void set_bit(T &x, int n) { x |= T(1) << n; }
or something similar where you pass in x and return the answer, etc.
This also lets you have some sort of verification that 'n' is in
range, if you so desire.
Finally, if x were an enum, you would probably cast it to something
before calling these functions (or not do bit manipulation
on enums