问题
This is the code I am going to use to take a set of three booleans and convert it into an int for a switch statement:
int bits = 0;
bool a = true, b = false, c = true; // 101 = 5
bits = bits | a << 2;
bits = bits | b << 1;
bits = bits | c;
cout << bits;
I have eight cases based on the combined state of these three booleans. Am I doing this right?
Right, not in the sense of the syntax although if there are any problems there please advise. More right in the sense of "Is this the best way to solve this problem?"
回答1:
If you are using C++, you could use bitset<N>.
回答2:
You're doing it right. You could make the code a little more succinct though:
bits |= (a<<2) | (b<<1) | (c<<0);
Just be aware that the Standard doesn't enforce any size constraint on bool. Pragmatically speaking there shouldn't be a problem with three bits, but the Standard doesn't back you here.
回答3:
$ cat ttt.c
//example of C solution
#include <stdio.h>
int main() {
union {
unsigned int val;
struct {
unsigned a : 1;
unsigned b : 1;
unsigned c : 1;
//unsigned d : 1;
//e, f, g, h...
} flags;
} bits;
bits.val=0;
bits.flags.a = 1;
bits.flags.c = 1;
printf("val: %d\n",bits.val);
return 0;
}
~$ ./ttt
val: 5
回答4:
I would do it as:
bits = (bits << 1) | a;
bits = (bits << 1) | b;
bits = (bits << 1) | c;
which would require less maintenance work if you needed to add or to remove a flag.
However, doing this so that you can use it for a switch sounds like it might be a bad idea. Adding a flag would double the number of states you'd need to handle, and the case values would be fragile and hard to read.
But if you really must, here's another approach:
enum
{
c_bit_offset,
b_bit_offset,
a_bit_offset
};
unsigned int bits = (a << a_bit_offset)
| (b << b_bit_offset)
| (c << c_bit_offset);
switch (bits)
{
case 0:
/* Do something. */
break;
case (1 << a_bit_offset):
/* Do something. */
break;
case (1 << a_bit_offset) | (1 << b_bit_offset):
/* Do something. */
break;
...
}
By the way, you probably should use unsigned int instead of int.
回答5:
You can make some defines to make easy to work with bits
#define BitSet(arg,bit) ((arg) |= (1<<bit))
#define BitClr(arg,bit) ((arg) &= ~(1<<bit))
#define BitFlp(arg,bit) ((arg) ^= (1<<bit))
#define BitTst(arg,bit) ((arg) & (1<<bit))
Then you can use only one char
keys = 0b00000101;
BitSet (keys,1);
This an common way to work in embedded systems.
回答6:
You can always do the conversion explicitly:
bits = bits | (a ? 1 : 0) << 2;
However I believe C/C++ will handle it implicitly, once you're using the bit-shift operator.
You should define constants for each flag, giving a name to the bit you are setting:
const int a_flag = 2;
bits = bits | (a ? 1 : 0) << a_flag;
Edit:
As you can see from the comments on my answer, most C/C++ programmers prefer to learn implicit conversions and operator precedence. Therefore your original code is "most correct".
Edit 2:
Except, you should use the |= operator:
const int a_flag = 2;
bits |= a << a_flag;
来源:https://stackoverflow.com/questions/3443751/converting-a-set-of-booleans-to-a-number